Appendix A. WSO2 Web Services Framework for PHP

WSO2 Web Services Framework for PHP (WSO2 WSF/PHP) is an open-source, enterprise grade PHP extension for providing and consuming web services in PHP. The home page for the project can be found at http://wso2.org/projects/wsf/php. WSO2 WSF/PHP is a complete solution for building and deploying web services and is the only PHP extension with the widest range of WS-* (also known as SOAP web services) specification implementations. It is also notable that it has a comprehensive REST support. You can implement a single service and expose it as both SOAP and REST service. Please refer to Chapter 1 for a recap of REST and SOAP comparison.

In Chapter 6 we introduced Zend Framework. The key difference between WSF/PHP and the Zend Framework is that, while Zend framework is a library written in PHP, WSF/PHP is a library written in C as a PHP extension. Also, while Zend Framework is a generic PHP library that also includes REST support. WSF/PHP is a web services specific framework that supports REST as well as SOAP services. You can use WSF/PHP as a REST framework alone or you can use it for SOAP web services that require quality of service aspects such as security and reliability.

Since WSF/PHP is implemented in C, you can expect to have better performance while using it as compared to using a library written in PHP alone such as Zend Framework. However, the performance gain comes with a cost, that being the complexity of installing compiled C libraries as a PHP extension. Whereas a library written in PHP, such as Zend Framework, can be just copied to the document root and you are ready to use it.

Installing WSF/PHP

There is a comprehensive installation guide available online http://wso2.org/project/wsf/php/2.0.0/docs/install_guide.html. This guide explains Windows and Linux operating system specific steps that need to be followed in order to install the extension.

Implementing Services

There is a PHP class named WSService that comes with WSO2 WSF/PHP.

When you are implementing a service, you need to provide the set of operations and the set of REST semantics, including HTTP method and resource location.

Let's see how we can implement the book resource of the library system sample with WSO2 WSF/PHP.

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

Operations and REST map are arrays provided to the service. The call to reply() method indicates that the service should go ahead and process the request.

Here is the operations array.

$operations = array (
"getBooks" => "getBooksFunction",
"addBooks" => "addBooksFunction"
);

What we are doing here is that we map service operations to PHP functions that implement those operations. As an example, the getBooks operation would be handled by a function with the name getBooksFunction, defined in the PHP script. Note that these functions can take parameters, which we will see later in this chapter. However, when we define the options array, it is not required to mention the parameters of the functions. It is sufficient to mention only the name of the function irrespective of the type or number of parameters the functions would be accepting.

Here is the REST mapping array.

$restmap = array (
"getBooks" => array (
"HTTPMethod" => "GET",
"RESTLocation" => "book"
),
"addBooks" => array (
"HTTPMethod" => "POST",
"RESTLocation" => "book"
)
);

In here, we are providing the REST characteristics for the operations. As an example we specify that the getBooks operation would only respond to the GET requests and addBooks would respond to the POST requests. And both these operations are mapped to the location book. If the name of the PHP script with the service implementation is library.php and located in the folder /rest/09, the resource URL would be http://localhost/rest/09/library.php/book. As we saw in Chapter 4, while designing the sample Library service, a given business operation on a given resource does not get mapped to more than one HTTP verb. Hence in the operation mapping array more than one operation can be mapped to the same resource URL but with different HTTP verbs.

This design nicely maps to the resource design that we looked at while discussing the library system in Chapter 5.

URI

HTTP Method

Collection

Operation

Business Operation

/book

GET

books

retrieve

Get books

/book

POST

books

create

Add book(s)

In the implementation, we can cleanly map the resource location URI, the HTTP method required and the business operation.

Here is the getBooksFunction.

functiongetBooksFunction($inMessage) {
$link = mysql_connect('localhost', 'sam', 'pass') or die('Could not connect: ' . mysql_error());
mysql_select_db('library') or die('Could not select database');
$query = "SELECT b.id, b.name, b.author, b.isbn FROM book as b";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$response = "<books>";
while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
$response .= "<book>";
foreach($line as $key => $col_value) {
$response .= "<$key>$col_value</$key>";
}
$response .= "</book>";
}
$response .= "</books>";
mysql_free_result($result);
mysql_close($link);
$outMessage = new WSMessage($response);
return $outMessage;
}

In here, we are not interested in the input parameter as we are not expecting any. However, the operation function syntax mandates to have one, as the framework would fill in that if there were any input.

The response building logic should look familiar to you. We connect to the database, query for the book information and prepare the response XML string.

Finally, in this function, we create an instance of WSMessage with the response XML string that we prepared and returned.

$outMessage = new WSMessage($response);
return $outMessage;

If there is a return value, it is expected by the framework that you always return a WSMessage instance from the function implementing the operation business logic.

Next, the add book operation.

function addBooksFunction($inMessage) {
$link = mysql_connect('localhost', 'sam', 'pass') or die('Could not connect: ' . mysql_error());
mysql_select_db('library') or die('Could not select database'),
$xml = simplexml_load_string($inMessage->str);
foreach ($xml->book as $book) {
$query = "INSERT INTO book (name, author, isbn) VALUES ('$book->name', '$book->author', '$book->isbn')";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
mysql_free_result($result);
}
mysql_close($link);
return;
}

In this operation, we pick the incoming XML request from the in message.

$xml = simplexml_load_string($inMessage->str);

Note that $inMessage is an instance of WSMessage class. WSMessage class captures the incoming XML request as a string and stores it in the str member variable.

And then create new book instances in the database which you are already familiar with.

Here is the complete PHP source code for the service.

<?php
function getBooksFunction($inMessage) {
$link = mysql_connect('localhost', 'sam', 'pass') or die('Could not connect: ' . mysql_error());
mysql_select_db('library') or die('Could not select database'),
$query = "SELECT b.id, b.name, b.author, b.isbn FROM book as b";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$response = "<books>";
while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
$response .= "<book>";
foreach ($line as $key => $col_value) {
$response .= "<$key>$col_value</$key>";
}
$response .= "</book>";
}
$response .= "</books>";
mysql_free_result($result);
mysql_close($link);
$outMessage = new WSMessage($response);
return $outMessage;
}
function addBooksFunction($inMessage) {
$link = mysql_connect('localhost', 'sam', 'pass') or die('Could not connect: ' . mysql_error());
mysql_select_db('library') or die('Could not select database'),
$xml = simplexml_load_string($inMessage->str);
foreach ($xml->book as $book) {
$query = "INSERT INTO book (name, author, isbn) VALUES ('$book->name', '$book->author', '$book->isbn')";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
mysql_free_result($result);
}
mysql_close($link);
return;
}
$operations = array (
"getBooks" => "getBooksFunction",
"addBooks" => "addBooksFunction"
);
WSServicePHP source code$restmap = array (
"getBooks" => array (
"HTTPMethod" => "GET",
"RESTLocation" => "book"
),
"addBooks" => array (
"HTTPMethod" => "POST",
"RESTLocation" => "book"
)
);
$service = new WSService(array (
"operations" => $operations,
"RESTMapping" => $restmap
));
$service->reply();
?>

Implementing Clients

Implementing clients with WSF/PHP is very simple. Here is the code to list the books.

<?php
$requestPayloadString = <<<XML
<getBooks>
<book/>
</getBooks>
XML;
try {
$client = new WSClient( array("to" => ""http://localhost/rest/09/library.php/book",
"useSOAP" => FALSE,
"HTTPMethod" => "GET"));
$responseMessage = $client->request($requestPayloadString);
printf("Response = %s <br>", htmlspecialchars($responseMessage->str));
} catch (Exception $e) {
if ($e instanceof WSFault) {
printf("Error String: %s
", $e->str);
printf("HTTP Code : %s
", $e->httpStatusCode);
} else {
printf("Message = %s
",$e->getMessage());
}
}
?>

There is a PHP class named WSClient that comes with WSO2 WSF/PHP. While creating the client object instance you can provide an array of options. The options could include the endpoint address of the service, the"to" option. To make use of REST you have to set the"useSOAP" to FALSE. You can also specify the HTTP method to be used with"HTTPMethod" option.

$client = new WSClient( array("to" => "http://localhost/rest/09/library.php/book,
"useSOAP" => FALSE,
"HTTPMethod" => "GET"));

Then you send the request and receive the response.

$responseMessage = $client->request($requestPayloadString);

In this sample the request payload could be empty but in case you want to send a set of query parameters, you can provide that as XML and the framework would encode that into a series of query parameters.

Finally, you can consume the response.

printf("Response = %s <br>", htmlspecialchars($responseMessage->str));

If there are any errors, you can use the exception model to deal with them with WSO2 WSF/PHP. In this sample, we have a try catch block.

} catch (Exception $e) {
if ($e instanceof WSFault) {
printf("Error String: %s
", $e->str);
printf("HTTP Code : %s
", $e->httpStatusCode);
} else {
printf("Message = %s
",$e->getMessage());
}
}

In case of errors, the framework would compose the error message to a WSFault instance.

Next we will see the client code that adds books.

<?php
$requestPayloadString = <<<XML
<books>
<book><name>Book7</name><author>Auth7</author><isbn>ISBN0007</isbn></book>
<book><name>Book8</name><author>Auth8</author><isbn>ISBN0008</isbn></book>
</books>
XML;
try {
$client = new WSClient( array("to" => ""http://localhost/rest/09/library.php/book",
"useSOAP" => FALSE,
"HTTPMethod" => "POST"));
$client->request($requestPayloadString);
} catch (Exception $e) {
if ($e instanceof WSFault) {
printf("Error String: %s
", $e->str);
printf("HTTP Code : %s
", $e->httpStatusCode);
} else {
printf("Message = %s
",$e->getMessage());
}
}
?>

The only differences in this client code and the previous GET client is the fact that we use a different XML request payload expected by the add operation. We use HTTP POST method instead of GET and the fact that we are not expecting a response from the server.

SOAP Service and Client

As mentioned earlier, one of the advantages of WSF/PHP framework is the ability to use a given service both as a REST style service as well as a SOAP style service.

The good news is that you do not need to change any code in the service script to make it a SOAP service. You can use the same service that we implemented under the service implementation section above and send a SOAP request to the service and receive a SOAP response from the service. It is a feature of WSF/PHP framework for services to respond to clients based on the request format the clients use.

In order to write a SOAP client for the same service we can use the same client code that we used in the above section for implementing REST client and do a few minor modifications.

The first modification is to change the URL slightly. In the REST client, while creating WSClient, we used the following "to" option.

"to" => "http://localhost/rest/09/library.php/book"

For the SOAP client, we have to modify this to

"to" => "http://localhost/rest/09/library.php"

Note that we have removed the trailing /book section from the URL. This is because, while using SOAP, unlike in the case of REST, we do not use the concept of a resource. We just have to use the name of the root service, in this case, library.php.

The next change is to instruct the client to use the SOAP message format. In the REST client, we used the option:

"useSOAP" => FALSE

For the SOAP client, we could use the option:

"useSOAP" => TRUE

We could also remove this option for the SOAP client because if this option is not present, WSClient class assumes the SOAP message format by default.

The third and final change required to convert the REST client to a SOAP client with the WSF/PHP is to remove the HTTP method option. In the REST client we used:

"HTTPMethod" => "GET"

In case of SOAP clients and services the usual HTTP method used is POST. In other words, while using SOAP, the HTTP verb being used is not significant. This is one of the key differences between the SOAP style services and REST style services.

Here is the complete source code for the SOAP client with WSF/PHP for the library service.

<?php
$requestPayloadString = <<<XML
<getBooks>
<book/>
</getBooks>
XML;
try {
$client = new WSClient( array("to" => "http://localhost/rest/09/library.php",
"useSOAP" => TRUE));
$responseMessage = $client->request($requestPayloadString);
printf("Response = %s <br>", htmlspecialchars($responseMessage->str));
} catch (Exception $e) {
if ($e instanceof WSFault) {
printf("Error String: %s
", $e->str);
printf("HTTP Code : %s
", $e->httpStatusCode);
} else {
printf("Message = %s
",$e->getMessage());
}
}
?>

If you use the SOAP client in place of the REST client, you would not see much behaviour difference in the client, in other words, both REST and SOAP clients would give you the same output. However, if you capture the messages that go over the wire while using the SOAP and REST clients and compare them, you will notice a drastic difference in the message formats.

Here is the REST request sent by the REST client.

GET /rest/09/library.php/book HTTP/1.1
User-Agent: Axis2C/1.5.0
Host: localhost

Here is the SOAP request sent by the SOAP client.

POST /rest/09/library.php HTTP/1.1
User-Agent: Axis2C/1.5.0
Content-Length: 177
Content-Type: application/soap+xml;charset=UTF-8
Host: localhost
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/ soap-envelope">
<soapenv:Header/>
<soapenv:Body>
<getBooks>
<book/>
</getBooks>
</soapenv:Body></soapenv:Envelope>

As you would immediately notice, the SOAP request is much more bulky than the REST request. This is one of the key criticisms that SOAP gets, and one of the key reasons why people prefer REST over SOAP.

You could notice the same in the responses as well. The response to REST client from the service would look like the following.

HTTP/1.1 200 OK
Date: Sun, 28 Sep 2008 02:58:25 GMT
Server: Apache/2.2.6 (Win32) mod_ssl/2.2.6 OpenSSL/0.9.8e PHP/5.2.5
X-Powered-By: PHP/5.2.5
Content-Length: 314
Content-Type: text/xml;charset=UTF-8
<books>
<book>
<id>1</id>
<name>Book1</name>
<author>Auth1</author>
<isbn>ISBN0001</isbn>
</book>
<book>
<id>2</id>
<name>Book2</name>
<author>Auth2</author>
<isbn>ISBN0002</isbn>
</book>
<book>
<id>3</id>
<name>Book3</name>
<author>Auth3</author>
<isbn>ISBN0003</isbn>
</book>
<book>
<id>29</id>
<name/>
<author/>
<isbn/>
</book>
</books>

The response from the service to the SOAP client would be:

HTTP/1.1 200 OK
Date: Sun, 28 Sep 2008 02:59:27 GMT
Server: Apache/2.2.6 (Win32) mod_ssl/2.2.6 OpenSSL/0.9.8e PHP/5.2.5
X-Powered-By: PHP/5.2.5
Content-Length: 453
Content-Type: application/soap+xml;charset=UTF-8
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header/>
<soapenv:Body>
<books>
<book>
<id>1</id>
<name>Book1</name>
<author>Auth1</author>
<isbn>ISBN0001</isbn>
</book>
<book>
<id>2</id>
<name>Book2</name>
<author>Auth2</author>
<isbn>ISBN0002</isbn>
</book>
<book>
<id>3</id>
<name>Book3</name>
<author>Auth3</author>
<isbn>ISBN0003</isbn>
</book>
<book>
<id>29</id>
<name/>
<author/>
<isbn/>
</book>
</books>
</soapenv:Body>
</soapenv:Envelope>

The difference between SOAP and REST response messages are not as drastic as the request messages, but still, note the wrapping elements that SOAP uses in the response compared to the REST response, that makes even the response message slightly larger.

When the number of interactions increase, the additional overhead in the SOAP messaging style would account considerable overhead. Hence REST style would be the preferred style.

However, there are situations where SOAP is being used in the industry, especially in the enterprise. If you want to sign and encrypt the messages to secure the interactions, and if you want to make the same secure interaction reliable, SOAP has provision for them and the bulky message format comes into use.

Summary

WSO2 WSF/PHP framework, http://wso2.org/projects/wsf/php, provides comprehensive support for implementing REST style services and clients. The framework provides an API that makes it easy to map design to the implementation.

In this chapter, we discussed how to use WSF/PHP service and client API to implement the sample library system as a REST service, and implemented a REST client to consume the same. We also looked into using the SOAP features provided in the frameworks to implement a SOAP client to consume the same service using SOAP style messages.

We also discussed the differences between REST and SOAP message styles.

You can try the samples that are available online at http://labs.wso2.org/wsf/php/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.77.117