WSO2 WSF/PHP Manual

1. Introduction

WSO2 Web Services Framework/PHP is a PHP extension that could be used to provide and consume Web services. It supports SOAP 1.1, SOAP 1.2, MTOM, WS-Addressing, WS-Security UsernameToken as well as REST style invocation.

2. Requirements

WSO2 Web Services Framework/PHP (WSO2 WSF/PHP) makes use of GNOME XML library.

3. Installation

This extension is available as an external extension. Please see the Installation Guide for more information.

4. Runtime Configuration

The behavior of this extension is governed by the following settings in php.ini.

Dynamic extension setting :
extension=wsf.so
This setting tells that the extension shared library would be named wsf.so and placed in extension dir.

In addition to the above setting, the following WSO2 WSF specific settings are required.

WSO2 WSF/PHP Configuration Options
Name Type Default Description Changeable
wsf.home string "/path_to_php_ext/wsf_c" Path to where you have WSO2 WSF/C installed. PHP_INI_ALL
wsf.log_path string "/tmp" Path to the folder into which the WSO2 WSF/PHP log file is to be written.
A log file named wsf.log will be written to this given location.
PHP_INI_ALL

Note: PHP_INI_ALL means that the entry can be set anywhere in the php.ini.

5. Quick Start Guide

This section is aimed to help you to get a Web service up in quick time using WSO2 WSF/PHP and consume that service using a WSO2 WSF/PHP client.

First follow the install guide and get WSO2 WSF/PHP working on your machine. Once you have installed the extension, you should be able to run the php scripts written using classes supported by WSO2 WSF, by dropping them into Apache2's htdocs folder, or where ever you have your web server root.
Make sure that you have edited your php.ini file, in accordance with the instructions in the Installation Guide.

Once you have WSO2 WSF up and running successfully, you can start writing your own services and clients.

Lets first see how you could write a client to consume the Google spell check service. First we need to prepare the payload, as expected by the service:

$reqPayloadString = <<<XML
<ns1:doSpellingSuggestion x:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:GoogleSearch" xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
        <key xsi:type="xsd:string">your_key_here</key>
        <phrase xsi:type="xsd:string">tamperature</phrase>
</ns1:doSpellingSuggestion>
XML;

In the above payload, you have to fill in your Google key in the "key" element. The "phrase" element contains the word that we want to spell check.

Next we need to create a WSClient, with the options to be used by the client. For the Google spell check service, we have to use two options, one is the endpoint address the request is to be sent to, the other is the SOAP version. Google spell check service use SOAP version 1.1.

        $client = new WSClient(array("to" => "http://api.google.com/search/beta2", 
                "useSOAP" => 1.1)); 

Once we have have the payload and the client ready, we can send the request and receive the response.

        $resMessage = $client->request($reqPayloadString);
    
        printf("Response = %s <br/>\n", htmlspecialchars($resMessage->str));

Here is the complete source code for this Google spell check client : google_spell.php. Please remember to replace "your_key_here" string with a valid Google key.

The following sections detail how to write a simple service and a client with WSO2 WSF/PHP.

5.1. Hello Service

Lets see how you could write your first Web service with WSO2 WSF/PHP .

The first service that we are going to write is named "hello" and would have a single operation named "greet". This "greet" operation, when invoked by a client, would expect the client to send a greeting in request, and would in turn send a greeting in the response. Following are example XML payloads exchanged between client and service:

Request:

<greet>
    Hello Service!
<greet>

Response:

<greetResponse>
    Hello Client!
<greetResponse>

The steps to be followed when implementing a service with WSO2 WSF/PHP include:

  1. Write the functions corresponding to the operations of the service.
    In our sample, we will have one function that implements the "greet" operation.
    We would name that function "greet".
  2. Create a WSService giving the operations and/or actions map along with options.
    In our example, we have only one function, and we would use the name of the function as our operation name to keep things simple.
    Hence, we will keep things simple and use only the operation map to specify our single operation.
  3. Invoke the reply() method of the WSService class to invoke the operation and prepare the response.
    This step is a simple method call to indicate to the service to start processing the request. This step is the same for all services.

5.1.1. Operation Implementation

Following is the implementation of the greet operation:

function greet($message) {
 
$responsePayloadString = <<<XML
        <greetResponse>Hello Client!</greetResponse>
XML;
 
        $returnMessage = new WSMessage($responsePayloadString);
        
        return $returnMessage;
}

This function implements the business logic for the greet operation. Basically this function receives the request payload as a WSMessage object instance, prepares the response and returns as a WSMessage instance.

5.1.2. Service Instance Creation with Operations

A service could be created, specifying the operations as shown below:

$service = new WSService(array("operations" => array("greet")));

In the above code fragment, we create a service instance with "greet" operation. The "greet" function implemented above would be called when the "greet" operation is invoked with the service.


5.1.3. Replying to Service Invocations

$service->reply();

The reply() method of the service has to be called by all service implementations. This call would trigger the request processing on server side and prepare the response to be sent to client.

5.1.4. Full Source

Here is the complete source code for the service : hello_service.php


5.1.5. Deploying the Service

In order to make the service available to be consumed by clients, we have to deploy the service. To deploy the service, you just have to copy the php source file implementing the service to your Web root, just like you do with other PHP scripts. Lets name our service PHP script, hello_service.php.

To verify that your service has been correctly deployed, you can start the Web server and then browse the service script using a Web browser. For our sample, assuming the defaults for Web server, you can test the service with http://localhost/hello_service.php. You should get an entry for the hello_service.php on the page that you get.



5.2. Hello Client

Now that you know how to write a service with WSO2 WSF/PHP , let's see how you could write a client to consume that service. The request payload that the client would be sending to the service was described in the previous section. The client has to prepare the payload, send a request to the service and then receive and process the response.

The steps to be followed when implementing a client with WSO2 WSF/PHP include:

  1. Create a WSMessage instance with desired request payload and options.
    WSMessage constructor takes an array of options that helps to fine tune the request message sent from the client. As a minimum, you have to set the "to" option, indicating the endpoint reference of the service to be consumed.
  2. Create a WSClient instance
    You can use the WSClient instance to consume the service.
  3. Send the request and receive the response.
    Invoke the request() method passing the message as a parameter. This method returns a WSMessage instance, representing the response message. You can use member variables of the returned message instance to access the response in XML format.
  4. Consume the response
    Process the response in line with the client business logic.

5.2.1. Preparing Request Message

        $message = new WSMessage($requestPayloadString, 
                array("to" => "http://localhost/hello_service.php"));

In the above code fragment, a WSMessage instance is created with payload to be sent in the request and the service endpoint. The "to" element of the options array is mapped to the address of the location of the service. In other words, the "to" address indicates where the request should be sent to.


5.2.2. Sending Request and Receiving Response

        $client = new WSClient();
        
        $response = $client->request($message);

For sending a request with the output message created earlier, we need a WSClient instance. We pass the message to be sent to the service to the request() method. This will send the payload contained in the given message and receive the response and return a message instance with the response payload.


        echo $response->str;

In our client sample we access the response payload as a string from the returned message instance and echo it.

5.2.3. Full Source

Here is the complete source code for the client : hello_client.html


5.2.4. Running the Client

To run the client, copy the client php script to the Web root of your Web server, as done for the service script, and access the client from the Web browser.

6. Consuming Web Services

For consuming Web services with WSO2 WSF/PHP, using the XML in/out model, you need to first find out the request payload format and the response payload format. You also need to know the service endpoint URI.
Once those information is available, you can construct a WSMessage instance with the payload and service endpoint URI information. These are the minimum requirements for consuming a Web Service. These basics were explained in the quick start guide.

The advantage of using the WSO2 WSF extension is that it supports more than just SOAP. You can use WS-Addressing, XOP/MTOM and WS-Security UsernameToken when providing and consuming Web services. You can also invoke services using REST style calls.

The following sections explain how you can achieve more with the options available for WSMessage and WSClient.

6.1. Using SOAP

You can use the "useSOAP" option at client level to specify the SOAP version to be used. If this option is not set, the default SOAP version used is SOAP 1.2.

There are multiple ways of setting the SOAP version, you can use any one of them.

         // setting SOAP 1.2 version
        $client = new WSClient();
        $client = new WSClient(array("useSOAP" => TRUE));
        $client = new WSClient(array("useSOAP" => 1.2));
        $client = new WSClient(array("useSOAP" => "1.2"));
 
        // setting SOAP 1.1 version
        $client = new WSClient(array("useSOAP" => 1.1));
        $client = new WSClient(array("useSOAP" => "1.1"));

There is another option named "HTTPMethod", that you could use to specify the HTTP method to be used. When SOAP is in use, the default HTTP method used would be "POST" all the time. If you specify "GET" when SOAP is in use, then no request would be sent, because WSO2 WSF/PHP does not support SOAP with HTTP GET.

6.2. Using REST

If you want to consume Web services using REST style calls, that can be done by setting the "useSOAP" option to false. In case of REST style of invocation, you can use either HTTP POST method or HTTP GET method.

The following example shows how to enable a REST style invocation using different HTTP methods.

         // REST with HTTP POST
        $client = new WSClient(array("useSOAP" => FALSE));
        $client = new WSClient(array("useSOAP" => FALSE, "HTTPMethod" => "POST"));
        $client = new WSClient(array("useSOAP" => FALSE, "HTTPMethod" => "post"));
 
         // REST with HTTP GET
        $client = new WSClient(array("useSOAP" => FALSE, "HTTPMethod" => "GET"));
        $client = new WSClient(array("useSOAP" => FALSE, "HTTPMethod" => "get"));

6.3. Payload Formats

When invoking Web services, WSO2 WSF/PHP extension allows you to provide the message payload either directly as an XML string or as a WSMessage instance with the XML string stored inside it. In the future, you would be able to pass the payload in SimpleXMLElement and domDocument formats to the send() and request() methods of WSClient class. If you want to use those formats of XML as payload with this current release, you have to use the functions ws_request() and ws_send().

Using a string as the request payload:

$reqPayloadString = <<<XML
        <ns1:echoString xmlns:ns1="http://php.wsf.wso2.net/samples">
                <text>Hello World!</text>
        </ns1:echoString>
XML;
 
 
    $client = new WSClient(
        array("to"=>"http://localhost/echo_service.php"));
                                
    $resMessage = $client->request($reqPayloadString);


Using a WSMessage instance to represent request payload:

$reqPayloadString = <<<XML
        <ns1:echoString xmlns:ns1="http://php.wsf.wso2.net/samples">
                <text>Hello World!</text>
        </ns1:echoString>
XML;
 
    $reqMessage = new WSMessage($reqPayloadString);
 
    $client = new WSClient(
        array("to"=>"http://localhost/echo_service.php"));
                                
    $resMessage = $client->request($reqMessage);

WSO2 WSF/PHP extension only supports the XML in/out model for consuming services currently. Data binding for PHP would be supported in a future release.

6.4. Attachments with MTOM/XOP

WSO2 WSF/PHP allows you to send and receive binary data with SOAP messages using MTOM/XOP conventions. When sending attachments, you have to use a WSMessage instance to represent the payload, and give the binary data as an array. When receiving attachments, you can get the attachments received from the attachments array of the WSMessage instance returned.


For sending an attachment, you need to specify the element where the attachment reference should be included in the payload.

$reqPayloadString = <<<XML
<ns1:attach xmlns:ns1="http://php.wsf.wso2.net/samples/mtom">
               <ns1:fileName>test.jpg</ns1:fileName>
               <ns1:image xmlmime:contentType="image/jpeg" xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
                  <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myid1"></xop:Include>
               </ns1:image>
</ns1:attach>
XML;

In the above sample payload shown, by placing the 'Include' element within the 'image' element, we specify that the attachment reference should be included in the 'image' element. The 'href' attribute of the 'Include' element gives the ID of the attachment element in the attachments array of the outgoing WSMessage instance. Once the payload is prepared, you have to create the message with the attachment data array containing the binary data to be attached.

        $f = file_get_contents("./resources/axis2.jpg");
    
        $reqMessage = new WSMessage($reqPayloadString, 
                array("to" => "http://localhost/mtom_service.php",
                "attachments" => array("myid1" => $f)));

In the above sample code fragment, we load the image contents to the '$f' variable and pass the variable to the attachments option when creating the message. In the attachments associative array, you have to give the same ID as was given in the 'Include' element's 'href' attribute in the payload. In this sample, we use 'myid1' as the ID.

When sending attachments, you can configure the client either to send the attachment in the optimized format or in non optimized format. If the attachment is sent in binary optimized format, the file content would be sent as it is, out of the SOAP body, using MIME headers and the payload would have an XOP:Include element, referring to the MIME part that contains the binary attachment.
In case of binary non optimized format, the attachment content would be sent in the payload itself, as a base64 encoded string.

        // send attachments binary optimized
        $client = new WSClient(array("useMTOM" => TRUE));
        
        // send attachments binary non-optimized
        $client = new WSClient(array("useMTOM" => FALSE));

6.5. Using WS-Addressing

WS-Addressing provides mechanisms to address Web services and messages. With WSO2 WSF/PHP, you can use both WS-Addressing version 1.0 as well as the submission version.

There are two basic requirements for using WS-Addressing on client side with WSO2 WSF/PHP. One is that you have to provide a WS-Addressing action at message level. The other is that you have to enable the use of WS-Addressing at client level.

 
    $reqMessage = new WSMessage($reqPayloadString,
        array("to"=>"http://localhost/echo_service_addr.php",
              "action" => "http://php.wsf.wso2.net/samples/echoString"));
              
    $client = new WSClient(array("useWSA" => TRUE));

In the above shown sample code fragment, the WS-Addressing action is set using the "action" array element of the options array passed to the WSMessage constructor. WS-Addressing is enabled with the "useWSA" option passed to WSClient constructor.

You can choose to use different addressing versions as shown below. You have to use one of the possible options shown below.

    // Setting WS-Addressing 1.0
    $client = new WSClient(array("useWSA" => TRUE));
    $client = new WSClient(array("useWSA" => 1.0));
    $client = new WSClient(array("useWSA" => "1.0"));
    
    // Setting WS-Addressing submission
    $client = new WSClient(array("useWSA" => "submission"));

In addition to the action, there are other WS-Addressing related SOAP headers that could be sent in a message. WSO2 WSF/PHP has support to set those headers as properties at the message level or as options at the client level. An example is shown below.

    $reqMessage = new WSMessage($reqPayloadString,
        array("to" => "http://www.company_foo.com/order_processing.php",
              "action" => "http://php.wsf.wso2.net/samples/order",
              "from"  => "http://www.company_bar.com/place_order.php",
              "replyTo" => "http://www.company_bar.com/billing.php",
              "faultTo" => "http://www.company_bar.com/re_oder.php"));
    
    $client = new WSClient(array("useWSA" => TRUE));

In the above example, company "bar" sends a purchase order to company "foo" from the place order client. If the service invocation is successful, company foo would send the bill to the billing service of company bar; if the order failed, re-order service of company bar would be sent the fault details which would decide how to place the order again. WS-Addressing helps us to manage the order process, with replies and faults being directed to differently addressed endpoints.

6.6. WS-Security

With WSPolicy and WSSecurityToken, you can use WS-Security usernameTokens, encryption, signing, along with timestamp, time-to-live and digest support. The simplest form of using usernameToken is to provide a username and a password.

    $policy_obj = new WSPolicy(array("useUsernameToken" => TRUE));

    $security_obj = new WSSecurityToken(array(
              "user" => "john",
              "password" => "fred"));
Or else user can use the password call back mechanism by using a callback function.

 function passwordFunction($username)
{
/** some  mechanism to retrive the password */

}


Then WSSecurityToken object would be
      $security_obj = new WSSecurityToken(array(
              "user" => "john",
              "password_callback" => "passwordFunction"));

If user wants timetoLive and timestamp , those options also can be specified.
     $policy_obj =new WSPolicy(
        
  array( "useUsernameToken" =>TRUE,
              "includeTimestamp"=>TRUE));

    $security_obj = new WSSecurityToken(array(
              "user" => "john",
              "password" => "fred",
              "ttl" => 300));

   

6.7. One-Way Clients

The request() method of WSClient that you have seen in the samples so far adheres to the out-in message exchange patterns. That means, when the client sends a request, it expects a response back.
Out-only message exchange pattern is another popular pattern when consuming services. In out-only model, client sends a request but does not expect a response back. The send() method of WSClient supports this message exchange pattern.

    $client = new WSClient(
        array("to"=>"http://localhost/notify_service.php"));
                                
    $client->send($reqPayloadString);
    
    printf("Request sent\n");

In the above sample, the notify service accepts the payload sent by the client and consumes it, and would not send any response. The return type of send() is void. In case of errors, it would throw a fault.

6.8. Consuming Web Services using Function API

WSO2 WSF/PHP provides a function based API, in addition to the object oriented API that you have already seen, to provide and consume services. There are two functions that you can use on client side, ws_request() and ws_send().

In order to use these functions, you have to copy the wsf.php file that is located in the scripts sub folder of the distribution, to your Web server's document root. Once that is done you have to include that script in your source, before using the API.

include_once('./wsf.php');

Once that file is included, you are ready to use the functions.
The following code fragment shows how a two way client invocation could be done, sending a request and receiving a response.

$reqPayloadString = <<<XML
    <ns1:echoString xmlns:ns1="http://php.wsf.wso2.net/samples">
        <text>Hello World!</text>
    </ns1:echoString>
XML;

    $resMessage = ws_request($reqPayloadString, 
                        array("to"=>"http://localhost/echo_service.php"));
    
    printf("Response = %s <br>", htmlspecialchars($resMessage->str));


In the above sample, you could have used a WSMessage instance, in place of the string payload, similar to the way it was done in object oriented code.

    $reqMessage = new WSMessage($reqPayloadString, 
                        array("to"=>"http://localhost/reply_service.php"));
    
    $resMessage = ws_request($reqMessage);
    
    printf("Response = %s <br>", htmlspecialchars($resMessage->str));


The following code fragment shows how a one way client invocation could be done, just sending a request without expecting a response.

$reqPayloadString = <<<XML
        <ns1:notifyString xmlns:ns1="http://php.wsf.wso2.net/samples">
                <text>Hello World!</text>
        </ns1:notifyString>
XML;
 
    ws_send($reqPayloadString,
               array("to"=>"http://localhost/reply_notify_service.php"));


Again, if you wish, you can use a WSMessage instance as the payload message.


7. Providing Web Services

For providing Web services with WSO2 WSF/PHP, using the XML in/out model, you need to first define the request payload format and the response payload format for each operation of the services that you intend to provide. For each operation in a service, once those payload formats are defined, you have to implement the functions that process the incoming request and generate the response message corresponding to each operation. When invoking a function mapped to a service operation, WSO2 WSF passes a WSMessage object instance to that function and expects that function to return a WSMessage object instance.
Hence the API for a user implemented function mapping to a service operation is as follows.

  WSMessage user_defined_operation(WSMessage payload)

Following code fragment shows an example:

function echoFunction($inMessage) {
 
    $returnMessage = new WSMessage($inMessage->str);
 
    return $returnMessage;
}

In the above sample, we just access the payload string in the incoming message and place it in the return message and return it. If you want to do further processing of the incoming payload, you could do that by processing the str member of the incoming message.

Once the functions taking care of the business logic processing are implemented, those need to be mapped to the operations of the service. There are multiple ways of specifying this mapping.
The simplest form is to use the "operations" option and just give the function name. You have to keep in mind that if you give only the function name, WSO2 WSF/PHP would assume the operation name to be the same as the function name.

$server = new WSService(array("operations" => array("echoFunction")));

The importance of the operation name is that, in case WS-Addressing is not in use, the Web services engine would resolve the operation to be invoked by looking at the local name of the first child element of the request payload. So, for the above service to respond to a request, the request payload's root element must be "echoFunction".

$reqPayloadString = <<<XML
    <ns1:echoFunction xmlns:ns1="http://php.wsf.wso2.net/samples">
        <text>Hello World!</text>
    </ns1:echoFunction>
XML;

However, if you want the payload look different, you can do so by specifying the operation name.

$server = new WSService(array("operations" => array("echoString" => "echoFunction")));

Now the following payload would cause the service to execute echoFunction function.

$reqPayloadString = <<<XML
    <ns1:echoString xmlns:ns1="http://php.wsf.wso2.net/samples">
        <text>Hello World!</text>
    </ns1:echoString>
XML;

It is also possible to add an operation using "actions" option as shown below, by using just the function name. However, "actions" option is really meant to be used for mapping WS-Addressing actions to operations. Hence, it is recommended not to use this approach.

$server = new WSService(array("actions" => array("echoFunction")));


In the context of WSO2 WSF/PHP, a single PHP script with WSService processing logic would be treated as a single service. Therefore in a service PHP script, there has to be only one call to the reply() method on top of a WSService instance. The reply() method triggers the service to start processing the request and prepare the response.

// create service object instance
$server = new WSService(array("operations" => array("echoString" => "echoFunction")));
// trigger request processing, call necessary methods and send a response back
$server->reply();


As a given PHP script would be bound to a single URL, when hosted with a Web server, that associated URL would naturally become the service endpoint of that PHP script implementing the service logic.

As in the case of client side, WSO2 WSF/PHP extension supports more than just SOAP on server side as well. You can use WS-Addressing, XOP/MTOM and WS-Security UsernameToken when providing and consuming Web services.

The following sections explains how you can achieve more with the options available for WSService.

7.1. Using SOAP

On the server side, you do not have to specify any options to use SOAP, rather based on the version of SOAP used in the client request, service would reply with the correct SOAP version. Hence when writing service PHP scripts, you do not have to bother about the SOAP version.

7.2. Using REST

There is no REST support in the current version of WSO2 WSF, however, it this support would be available in a future release.

7.3. Payload Formats

As mentioned earlier, the WSO2 WSF/PHP engine invokes the user defined function mapping to the operation with an instance of a WSMessage object. The function implementation representing the service's operation can choose to consume the request in whatever format supported by the WSMessage class.
When returning the response, the function implementation representing the service's operation can choose to represent the response in whatever format supported by the WSMessage class.

7.4. Attachments with MTOM/XOP

When sending attachments, as in the case of client side, you have to use a WSMessage instance to represent payload, and give the binary data as an array in the operation implementation function. When receiving attachments, you can get the attachments received in the attachments array of the WSMessage instance passed to the operation implementation function.


For sending an attachment, you need to specify the element where the attachment reference should be included in the payload.

$reqPayloadString = <<<XML
<ns1:attach xmlns:ns1="http://php.wsf.wso2.net/samples/mtom">
               <ns1:fileName>test.jpg</ns1:fileName>
               <ns1:image xmlmime:contentType="image/jpeg" xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
                  <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myid1"></xop:Include>
               </ns1:image>
</ns1:attach>
XML;

In the above sample payload shown, by placing the 'Include' element within the 'image' element, we specify that the attachment reference should be included in the 'image' element. The 'href' attribute of the 'Include' element gives the ID of the attachment element in the attachments array of the outgoing WSMessage instance. Once the payload is prepared, you have to create the message with the attachment data array containing the binary data to be attached.

        $f = file_get_contents("./resources/axis2.jpg");
    
        $resMessage = new WSMessage($resPayloadString, 
                array("attachments" => array("myid1" => $f)));

In the above sample code fragment, we load the image contents to the '$f' variable and pass that variable to the attachments option when creating the message. In the attachments associative array, you have to give the same ID as was given in the 'Include' element's 'href' attribute in the payload. In this sample, we use 'myid1' as the ID.

When sending attachments, you can configure the client either to send the attachment in optimized format or in non optimized format. If the attachment is sent in binary optimized format, the file content would be sent as it is, out of the SOAP body, using MIME headers and the payload would have an XOP:Include element, referring to the MIME part that contains the binary attachment.
In case of binary non optimized format, the attachment content would be sent in the payload itself, as a base64 encoded string.

 
// send attachments binary optimized
$server = new WSService(array("operations" => $operations, "useMTOM" => TRUE));
 
// send attachments binary non-optimized
$server = new WSService(array("operations" => $operations, "useMTOM" => FALSE));

When receiving attachments, the incoming message would have its attachments array set if there were MTOM optimized attachments in the request. So the user implemented function mapping to the operation can access them.

function getAttachment($inMessage) {
    
    $cid2stringMap = $inMessage->attachments;
    $cid2contentMap = $inMessage->cid2contentType;
    $imageName;
    
    foreach($cid2stringMap as $i=>$value){
        $f = $cid2stringMap[$i];
        $contentType = $cid2contentMap[$i];
        if(strcmp($contentType,"image/jpeg") ==0){
            $imageName = $i."."."jpg";
            file_put_contents("/tmp/".$imageName, $f);
        }
    }
    
$resPayload = <<<XML
<ns1:response xmlns:ns1="http://php.wsf.wso2.net/samples/mtom">Image Saved</ns1:response>
XML;
 
    $returnMessage = new WSMessage($resPayload);
 
    return $returnMessage;
}

In the above sample, the function responsible for processing the attachments goes through the attachments array and save each attachment, if it is a JPEG file. Once saved, it responds to the invoking client with the response payload.

7.5. Using WS-Addressing

Unlike on the client side, there is no need to enable WS-Addressing explicitly on server side. If the client request uses WS-Addressing, then the server side would respond with WS-Addressing. However, in order to make WS-Addressing meaningful, one has to specify the WS-Addressing action mapping for operations when constructing the service.

$operations = array("echoString" => "echoFunction");
$actions = array("http://php.wsf.wso2.net/samples/echoString" => "echoString");
 
$server = new WSService(array("operations" => $operations, 
                              "actions" => $actions));

In the above shown sample code fragment, the WS-Addressing action mapping is set for the echoString operation using the "actions" array. Note that it is not to the function name, but to the operation name that the WS-Addressing action is mapped.

The client requests could be using different WS-Addressing versions. The service reply would use the correct WS-Addressing version, based on the version used by the client. You do not have to explicitly specify the WS-Addressing version in the service script.

In addition to the action, the other WS-Addressing related SOAP headers that could be received in a message would be dealt with appropriately by the underlying Web services engine. As an example, if there is a replyTo set in the incoming message, the reply would be sent to the specified replyTo endpoint.

7.6. One-Way Operations

You can make your service operations adhere to either in-out message exchange pattern or in-only message exchange pattern. If a function mapped to an operation returns a WSMessage instance, then that operation is treated as an in-out operation. If a function mapped to an operation returns void, then that operation is treated as an in-only operation.
We have seen functions adhering to in-out message exchange pattern in samples given in the above sections including the quick start guide. The following is a sample of an in-only operation. .

function notifyFunction($inMessage) {
    // Do whatever desired processing of the in message here
    /* ... */
 
    return;
}

In the above sample, the notify function accepts the payload sent by the client and consumes it, and would not send any response.

7.7. Providing Web Services using Function API

The function based API has a function, namely ws_reply() that you can use on a service script to reply to client requests.

In order to use the function, you have to copy the wsf.php file that is located in the scripts sub folder of the distribution to your Web server's document root. Once that is done you have to include that script in your source, before using the API.

include_once('./wsf.php');

Once that file is included, you are ready to use the reply function.
The following code fragment shows how you could specify the operation mapping to use the function.

ws_reply(array("operations" => array("echoString" => "echoFunction")));