WSO2 WSF/PHP Manual

1. Introduction

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

2. Requirements

WSO2 Web Services Framework/PHP (WSO2 WSF/PHP) makes use of OpenSSL

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 indicates that the extension shared library will be named wsf.so and placed in the extension directory.

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_SYSTEM
wsf.log_path string "/tmp" or
"C:\Windows\Temp"
Path to the folder into which the WSO2 WSF/PHP log files will be written.
log files named wsf_php_client.log and wsf_php_server.log will be written to this given location.
PHP_INI_SYSTEM
wsf.log_level int 1 This is an integer value indicating the log_level to be used by the WSF/PHP
It can be one of the following values.
0 -> CRITICAL  ( Only critical errors will be logged )
1 -> ERROR      ( Errors will be logged)
2 -> WARNING  ( Errors and Warnings will be logged)
3 -> INFO       ( Errors , Warnings and Information will be logged)
4 -> DEBUG   ( All log messages including debug messages will be logged)
PHP_INI_SYSTEM
wsf.rm_db_dir int "/tmp" or
"C:\Windows\Temp"
This is the location where Sqlite database will be created when using Reliable Messaging.
If you are on a Linux/Unix platform ,make sure to specify a directory location has that has write permissions for the apache server.By default "/tmp" directory will be used. If you are on windows, make sure to specify directory with write permissions to apache server.
PHP_INI_SYSTEM
wsf.attachment_cache_dir int "/tmp" or
"C:\Windows\Temp"
This is the location where the cached attachments will be saved. This will happen only if you have enabled attachment caching and the attachment size if larger than 1 Mb.   PHP_INI_SYSTEM
wsf.enable_attachment_caching int When this is set, the attachment caching will happen if the attachment size if larger than 1Mb. That is, received attachments will be saved to the attachment cache directory. When sending attachments with this option set to 1 will send attachments in a memory efficient way. PHP_INI_SYSTEM

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

WSO2 WSF/PHP has a dependency on php_xsl extension. So enable the php_xsl extension by putting the entry

extension=php_xsl.so in php.ini.

Append the scripts folder path to your include_path entry in php.ini.

include_path = ".:/path_to_scripts_folder"

5. Quick Start Guide

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

First follow the installation 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. To do this drop them into the 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.

Let's first see how to 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 enter 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. The Google spell check service uses SOAP version 1.1.

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

Once we 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

Let's see how to 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, expects the client to send a greeting in request, and in turn sends a greeting in the response. The following are example XML payloads exchanged between the 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 will name that function "greet".
  2. Create a WSService giving the operations and/or actions map along with the options.
    In our example, we have only one function, and we will use the name of the function as our operation name to keep things simple.
    Hence, we will only use 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 it as a WSMessage instance.

5.1.2. Service Instance Creation with Operations

A service can 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 the "greet" operation. The "greet" function implemented above will 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 the server side and prepare the response to be sent to the 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. Let's 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 for the service script using a Web browser. For our sample, assuming the default values for the 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 can write a client to consume that service. The request payload that the client will 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 the desired request payload and options.
    The WSMessage constructor takes an array of options that help 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 the Request Message

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

In the above code fragment, a WSMessage instance is created with a 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 a Request and Receiving a 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 this 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 can use to specify the HTTP method to be used. When SOAP is in use, the default HTTP method used will be "POST" all the time. If you specify "GET" when SOAP is in use, then no request will 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 the HTTP POST method or the 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, the 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. If you have your payloads in SimpleXML or Dom you can use 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);

The WSO2 WSF/PHP extension supports the XML in/out model and WSDL mode for consuming services currently.

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 will 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 will 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 the 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 the 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 can be sent in a message. WSO2 WSF/PHP supports 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, you can use the password call back mechanism by using a callback function.

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

}


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

If you want the 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 the out-only model, the 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 will 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 the client side, ws_request() and ws_send().

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 can 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 can 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, they 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 will 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 to 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 the "actions" option as shown below, by using just the function name. However, the "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 will 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 will be bound to a single URL, when hosted with a Web server, that associated URL will naturally become the service endpoint of that PHP script implementing the service logic.

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

The following sections explain 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, the service will 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

The operations defined in your service can be exposed as REST style operations. You can map the operations of your service to a unique URI and to a HTTP method so that they can be accessed using REST Clients. Lets assume that a service has an operation echoString which should be available as REST operation with the url http://wos2.org/wsfphp/samples/echoService.php/echoString. This can be accomplished by specifying an array which mapps the operations to its corresponding HTTPMethod and a unique url which is constructed by concatenating the string provided in "RESTLocation" option with the service endpoint url.

$restmap = array("echoString"=>array("HTTPMethod"=>"POST","RESTLocation"=>"echoString"));

Now this array can be passed to the WSService constructor to expose operations in both REST and SOAP.

$service = new WSService(array("operations" => $operations, "RESTMapping"=>$restmap));

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 the 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 to either 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 will 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 saves 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 the 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, you have 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 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 may be using different WS-Addressing versions. The service reply will 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. For example, if there is a replyTo set in the incoming message, the reply would be sent to the specified replyTo endpoint.

7.6. Implementing Service Operations with in a class

WSF/PHP api allows you to implement a php class and expose methods of that class as operations of the Web Service. Lets take an example 'Foo' class which implements the 'bar' method.

class Foo{

      private $value = "";

      function Foo($value){

      $this->value = $value;

      }

      function bar($inMessage){

$requestPayloadString =  <<<XML <ns1:echoStringResponse xmlns:ns1="http://wso2.org/projects/wsf/php">

<value>$this->value</value></ns1:echoStringResponse> XML;

 new WSMessage($requestPayloadString);

      }

}

Here we are implementing the bar method that would take a WSMessage object and return a response WSMessage object.You need to specify to the WSService constructor that, class Foo's bar method should be exposed as an operation of the service.

Following is how to do it.

$ops = array("echoString"=>"bar");

$constructor_args = array("Hello World");

$service = new WSService(array("classes"=>array("foo"=>array("operations"=>$ops, "args"=>$constructor_args))));

You can implement multiple classes and expose methods of those classes as operations of the same service. To facilitate this WSService constructor options array takes an argument "classes" as an array.With in this array you can specify the operations and the constructor arguments as an associative array against the class names as demonstrated above.

7.7. One-Way Operations

You can make your service operations adhere to either the in-out message exchange pattern or the 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 does not send any response.

7.8. Providing Web Services Using Function API

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

include_once('./wsf.php');

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

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