Here is a problem that many people have asked me how to do it. “Returning an array of string” with the code first approach. The API or WSDL generation annotation guide, http://wso2.org/project/wsf/php/2.0.0/docs/wsdl_generation_api.html contain all the things required in details. Here is an example of a service that return an array of string.

<?php

/** splitMe function
 * @param string $string_to_split string to split
 * (maps to the xs:string XML schema type )
 * @return array of string $result split to array
 *(maps to the xs:double XML schema type )
 */
function splitMe($string_to_split)
{
    return array("result" => split(":", $string_to_split));

}

$operations = array("splitMe"=>"splitMe");
$opParams = array("splitMe"=>"MIXED");

$svr = new WSService(array("operations"=>$operations,
                           "bindingStyle"=>"doclit",
                           "opParams"=>$opParams));

$svr->reply();
?>

Note that the annotation corresponding to the return value.

 * @return array of spring $result split to array

This will generate an schema with an element of maxOccurs=’unbounded’. Note that you can get the wsdl from the ’serviceurl?wsdl’.

<xsd:element name="splitMeResponse">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element name="result" maxOccurs="unbounded" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:element>

Now just generate a client for this service using wsdl2php and try invoke it. You will get an array of string as the response.

    $input = new splitMe();
    $input->string_to_split = "a:b:c:d";

 
    // call the operation
    $response = $proxy->splitMe($input);
    print_r($response);

Apache Stonehenge, A project to demonstrate the interoperability between heterogeneous platforms has done their first milestone release few days back.

The first milestone demonstrate the interoperability between

  1. .NET – Microsoft WCF implementation
  2. Java – WSO2 Web Service Application Server (WSAS) implementation
  3. PHP – WSO2 Web Service Framework for PHP (WSF/PHP) implementation

Each of these technologies has implemented a Stock trader application with Business Service, Order Processor and Trader Client components. You will be able to assemble the application by mixing components from any of the above implementations.

It provides you a great sample on using basic web services features (SOAP, WSDL etc..) and WS-Security across the above platforms.

If you are interested, you can download the sources and binaries from here, http://www.apache.org/dist/incubator/stonehenge/. Installation guides and other documentations can be found from here, http://cwiki.apache.org/STONEHENGE/

In this case study “ PHP Data Services Extract Content from Drupal Database“, I intended to present how Data Service concepts can be applied to extract data with marketing value from  a CMS database and publish it as web services.  I used the drupal instance deployed at http://wso2.org as the CMS for the use case. And as the data service framework, I used WSF/PHP data services library, as it requires minimum changes to the existing infrastructure (the LAMP stack).

The case study also talks about how to consume the data service by any third party mashup to present textual/ graphical views of analyzed data. These mashups can be extended up to intergreate with social networks like facebook, twitter and etc to communicate back and forth a wider community and may be it can be used to track the distribution of active users using Google maps. Simply it makes easier to analyze business data + engagement with the community.

Now you can view the article I wrote titling “Introduction to PHP Data Services“. There I explain how you can design and implement Data Services in PHP using WSF/PHP Data Services Library.

This article covers,

  1. Designing your Data Service API.
  2. Writing the Data Service.
  3. Deploying and Testing Data Service.
  4. Make the Data Service available in both SOAP and RESTful form.
  5. Use of WS-* features in your Data Service.

If you are thinking of adapting SOA in to your database backed PHP applications, this article will be a good starting point.

PHP is one of the famous choice, when it comes to develop a web site. As the web evolve with the emerge of web service, REST (REpresentational State Transfer) concepts, the PHP language is also adapted to the new requirements specially with the availability of new SOA (Service Oriented Architecture), REST frameworks and libraries. Anyway there were hardly any guides, references or samples that properly describe the methodologies of developing REST applications using PHP.

The book “RESTful PHP Web Services‘ by Samisa Abeysinghe certainly fill this gap. It can be used as a step by step guideline for newbies to learn the concepts and write simple RESTful PHP applications and Mashups. And even experienced developers would find this a great reference to keep nearby while working with RESTful Web Services in PHP. And it has lot of code samples, utility functions that developers can use it in their applications.

RESTful PHP Web Services - Samisa Abeysinghe

About the Author

Samisa Abeysinghe is a well recognized name in the web services world. He lead the development of Apache Axis2/C and WSO2 WSF/PHP, two famous open source web service frameworks for ‘C’ and PHP. In addition to his deep knowledge in the subject, his experience in involving with the community and the enterprise for years and working as a lecturer in universities, should have influenced a lot in writing this book.

The Arrangement and the Content

The arrangement of the book is done really well to make sure the reader can go through it in the right sequence. All the content is bundled just within 200 pages. So you don’t need to allocate a lot of time to go through the whole book. It is organized into 7 chapters and two appendixes which are mostly independent from each other.

The first chapter is completely devoted to explain the concepts of RESTful web services. It basically explains what is RESTful web service and why it is needed. And it briefly mentions about the currently available REST Frameworks for PHP.

The second chapter introduce some PHP codes that do REST web service requests and handles the XML responses using both DOM and SimpleXML APIs. And in the third chapter it shows more code samples specially about consuming real world web services like BBC, Yahoo and an earthquakes information service. Theses codes are written as mashups mostly combining two services to produce more meaningful information.

The forth chapter is about  designing and writing web service providers. Its counterpart, writing web service consumers is described in the chapter five. There it demonstrate a library system that operate using RESTful webservices. You can map this example to any system that you may like to develop to run with RESTful web services. The chapter five of the book is available as a free download, RESTful PHP Web Services – Chapter 5.

The forth and fifth chapters are not using any framework to write the sample codes on consuming and providing web services. But in the sixth chapter it shows the use of Zend framework to do write them. There it rewrites the same example (The RESTful library system) in MVC (Model -View – Controller) approach using the functionalities of Zend framework. (In fact the View in the service is omitted).

The seventh chapter is about debugging web services. Debugging is a much needed step in any software development cycle. So if you are a newbie, you should read this chapter before start writing any of your own code. This introduces tools and methodologies to make your debugging easy and effective.

The book contains two appendixes. They are too really useful as the chapters of the book. In the first appendix it explains another REST web service framework, WSO2 Web Services Framework for PHP (WSF/PHP). To demonstrate it uses, some selected functionalities of the example library system (that is mentioned in chapters 4, 5, 6) is re-implemented using WSF/PHP. And it shows you how you can convert this RESTful system to a SOAP system in a minute. The second appendix provides you a code of a class (RESTClient), that you can use in consuming web services very effectively.

Recommended Readers

This book assume you have some knowledge in PHP. But it doesn’t require you to know anything related to web services, REST or XML. As you read the first few chapters, you will have a good understanding on the concepts and the basic applications of REST and XML using PHP. And the later chapters will guide to get deeper knowledge in writing complex and real world applications.

If you are a professional developer, you can skip the introduction chapters and jump directly to where you need to refer. For an example, if you use this book as a reference in designing and developing RESTful web service providers, you can directly read the chapter4 – Resource Oriented Services, chapter6- Resource Oriented Clients and Services with Zend Framework and probably the chapter 7 – Debugging Web Services.

This book contains the same example system (the library system) written in three different approaches, first without using any framework support, second using the Zend Framework, third using WSF/PHP. Each of them has its own pros and cons. So if you want to determine the approach more suitable to your requirements, or thinking of migrating from one to another, this book will be an ideal resource for you.

As you may have already noticed, this book contains lot of code samples. All the concepts are followed by simple code samples that explain the concept. In appendix it gives you a complete code for RESTClient class that you can use to call any REST service. Apart from the code of the example library system written using different frameworks, it has lot of codes for calling public web service APIs. And the explanation of the code is also done really well.

So it is clear this book is more targetting readers who like to implement PHP RESTful Systems in practice. And it covers enough concepts that you needed to know in writing practicle applications. So this book can take you from the zero knowlege to a deeper knowlege of RESTful PHP Web Services.

Same as web pages, web services also sometime require  client authentication. The most frequent way of authentication is the use of WS-Security Username token which authenticate clients based on the username and passwords. There can be situations where clients need to be authenticated based on its IP or its domain.

If you are writing web services from PHP (Using some PHP web service framework like WSF/PHP), You can use the PHP variables, $_SERVER["REMOTE_ADDR"] and $_SERVER["REMOTE_HOST"] to find the clients ip within the service logic code. If the client’s IP is static you can directly use the $_SERVER["REMOTE_ADDR"] and if it is dynamic you can use the $_SERVER["REMOTE_HOST"] which will be derived by reverse DNS look of the clients IP.

Here is one example of the use of these $_SERVER[] variables inside service logic.

 
function members_only_func($in_message) {

    // getting the clients IP.
    $remote_addr = $_SERVER["REMOTE_ADDR"];

    if($remote_addr == "67.205.26.154" ||
       $remote_addr == "124.43.59.95") {
       // generates the message for authenticated clients.

       return $valid_out_message;
    }

    // otherwise throw an exception
    throw new WSFault("Sender", "Failed to Authenticate");
}

$operations = array("membersOnlyOp" => "members_only_func");

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

$service->reply();

Web services has made the communication between heterogeneous environments (say PHP with .NET  or Java) a reality. It has defines standards for communicate not only with texts but also with binaries. And more importantly you can keep these communication confidential using encrypted messages according to your requirement. In this post, we will look at how we can implement such a system with PHP in one side.

In web services we can send/receive binary messages in two basic forms.

  1. Setting the binary inside the SOAP message. – Binary should be converted to base64 to make sure the SOAP body contains only texts. Since base64 converted data span longer than the binary data, we call this form as non-optimized way of sending binaries.
  2. Setting the binary outside the SOAP message – Binary would be sent as a MIME part in the message. And some element inside SOAP body keeps a reference to the binary using the MIME id. MTOM is a standard for referencing the MIME from inside the SOAP body. Since the binary is encoded, this will keep the message optimum with the binaries.

In WSF/PHP you can use any of these methods as you prefer. Lets forget about the encryption for now. We will check how we can send binaries in both of the above mentioned forms.

// first the request xml. Note tht xop:Include element that is referring the attachment with the id "myid1".
$reqPayloadString = <<<XML
<ns1:upload xmlns:ns1="http://wso2.org/wsfphp/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:upload>
XML;

try {
    $f = file_get_contents("my_binary_file.jpg");

    // here in the attachments option we define the binaries
    // corresponding to the id defined in the above XML
    $reqMessage = new WSMessage($reqPayloadString,
                                array("to" => "http://localhost/simple_upload_service.php",
                                      "action" => "http://wso2.org/upload",
                                      "attachments" => array("myid1" => $f)));

    // creating the WSClient
    // here the option useMTOM will decide whether the
    // attachment is set MTOM or base64
    $client = new WSClient(array("useWSA" => TRUE,
                                 "useMTOM" => TRUE));

    // sending the message and retrieving the response
    $resMessage = $client->request($reqMessage);

    printf("Response = %s \\n", $resMessage->str);

} catch (Exception $e) {

    if ($e instanceof WSFault) {
        printf("Soap Fault: %s\\n", $e->Reason);
    } else {
        printf("Message = %s\\n",$e->getMessage());
    }
}

As mentioned in the inline comment we can choose the preferred form of sending binary using the “useMTOM” option. if it is true, the binary is set as a MTOM, (referencing from the body) or if it is set false, the binary will be set as a base64 binary within the SOAP body.
To encrypt the message you only need to write few additional lines. First you define your policy that you need to encrypt this message using a WSPolicy object. Then the security token including the service public key and your private key. You need to give these two option as a constructor argument in WSClient. Here is that little additional code you need to write to add the encryption.

    // loading the keys
    $rec_cert = ws_get_cert_from_file("receiving_server.cert");
    $pvt_key = ws_get_key_from_file("my_private_key.pem");

    // here we defines the policies and create WSPolicy object
    $sec_array = array("encrypt" => TRUE,
                       "algorithmSuite" => "Basic256Rsa15",
                       "securityTokenReference" => "IssuerSerial");

    $policy = new WSPolicy(array("security" => $sec_array));

    // defining Security Tokens
    $sec_token = new WSSecurityToken(array("privateKey" => $pvt_key,
                                           "receiverCertificate" => $rec_cert));

    // modifing WSClient with adding WSPolicy and WSSecurityToken object
    $client = new WSClient(array("useWSA" => TRUE,
                                 "useMTOM" => TRUE,
                                 "policy" => $policy,
                                 "securityToken" => $sec_token));

You can implement the receiving side of the message similar to the sending side that we just described above. The most important thing is it doesn’t need to be written in PHP. It can be a Java code or .NET code.If you already have web services that use encrypted binary messaging, the above php code can be use out of the box to communicate with it.

LAMP (Linux + Apache + Mysql + PHP) stack powers many servers in the Internet today. For a LAMP  server, PostgreSQL could be the first alternative to Mysql. Similar to PHP + MySQL,  PHP + PostgreSQL too can be easily used in to host data services. Here are the steps to do it.

  1. If you already don’t have Apache + PHP + PostgreSQL download them from the following locations. Apache – http://httpd.apache.org/download.cgi, PHP – http://php.net and PostgreSQL – http://www.postgresql.org/download/
  2. You have to enable the PHP pdo_pgsql, pdo and pgsql plugins. Read here for the instructions to setup these libraries. (For an example: if you are windows you have to set the system ‘PATH’ variable to the <postgresql_installed_dir>/bin directory.
  3. If you already don’t have WSF/PHP, download and install it according to the guidelines provided in wsf/php installation guide.NOTE: You can check pdo_pgsql and wsf/php has properly installed with the help of phpinfo() function.
  4. Now lets start with creating a sample Database table. For this example I created a database called ‘workshop’, schema called ‘workshop’ and inside there the table ‘Employee’ with the following schema.
    Column Name Column Type
    employId integer
    name character varying
    email character varying
    jobTitle character varying
    project character varying

    Note: You can use phpPgAdmin (web based) or pgAdmin III to create tables from GUI

  5. Then you can write a small php script to expose the data in the above table as a web service.
    <?php
    
    //Including the Data Services library
    require_once("wso2/DataServices/DataService.php");
    
    // Including the connection information (i.e. PGSQUL USERNAME
    // and PGSQL_PASSWORD) for my PGSQL Connection
    require_once("constants.php");
    
    // database configurations
    $config = array(
    		"db" => "pgsql",
    		"username" => PGSQL_USERNAME,
    		"password" => PGSQL_PASSWORD,
    		"dbname" => "workshop",
    		"dbhost" => "localhost"
    		);
    
    $output_format = array(
                        "resultElement" => "employees",
                        "rowElement" => "employee",
                        "elements" => array(
    			    "id" => "employeeId",
                                "name" => "name",
                                "email" => "email",
                                "jobTitle" => "jobTitle",
                                "project" => "project"));
    
    $sql = "SELECT * FROM workshop.Employees";
    
    $get_employees_op = array("outputFormat" => $output_format, "sql" => $sql);
    
    $get_employees_url = array("HTTPMethod" => "GET", "RESTLocation" => "employees");
    
    // list of operations
    $operations = array(
                    "getEmployees" => $get_employees_op,
                    );
    
    // list of rest url mappping (operation => url)
    $restmap = array(
                    "getEmployees" => $get_employees_url,
                    );
    
    // creating DSService and reply
    $service = new DataService(array(
             "config" => $config,
             "operations" => $operations, "RESTMapping"=>$restmap));
    $service->reply();
    ?>
  6. We just wrote a PostgreSQL Data Services that provides its service as both REST and SOAP form. To deploy this service, We just need to copy this in to the web root directory. And the web URL for the script will be the endpoint to the web service.
  7. We can test the service either by calling its SOAP interface, which we may need to write a small SOAP client or by calling its REST interface, which only need a GET request from the browser. Say my script name is “my_dataservice.php” and I’ve put it in the web root directory, then the URL to call the REST interface of the service is
    http://localhost/my_dataservice.php/employees

WSDL Generation for PostgreSQL Data Service
You can get the WSDL for the service from the URL formed adding the suffix “?wsdl” (or “?wsdl2″ to wsdl v2.0) to the service URL,

http://localhost/my_dataservice.php?wsdl

Here all the schema data types are shown as xsd:anyType, which may not be the behavior that you want. In fact you can provide the schema data types to the fields from the code itself. Lets change the $outputFormat variable to provide the schema information as well using the following code snip.

$output_format = array(
                    "resultElement" => "employees",
                    "rowElement" => "employee",
                    "elements" => array(
			    "id" => array("column" => "employeeId",
		    			  "xsdType" => "xsd:int"),
			    "name" => array("column" => "name",
		    			  "xsdType" => "xsd:string"),
			    "email" => array("column" => "email",
		    			  "xsdType" => "xsd:string"),
			    "jobTitle" => array("column" => "jobTitle",
		    			  "xsdType" => "xsd:string"),
			    "project" => array("column" => "project",
		    			  "xsdType" => "xsd:string")));

Note that you provide the xsd type for each field explicitly. In fact this change is not needed for mysql pdo extension since it allows identifying field types programatically. Since this feature is not available in all the other pdo drivers, we have to explicitly give xsd type information for them.

If you wan to provide data services with SQLite or MSSQL, You can check my other posts on MSSQL(Microsoft SQL) Data Services In PHP and Data Services with SQLite in PHP.

With WSF/PHP Data Service library, you can convert a SQL query to a Data Service very easily in few steps.

  1. Decide your SQL query first, For the query you may require some input parameters, and you have to decide what should be returned by the query, Say your query is
    $sql_query = "SELECT name, age, email FROM users where country = ?";

    Then the “country” is our input parameter and the name, age, email are our return values.

  2. Define the input Format. For the above query it will be something like,
    $inputFormat = array("country" => "INT");
  3. Define the output format. We are giving the name “Users” for the out most wrapper element and the name “user” for the wrapper element of each user. Here is how we define it,
    $outputFormat = array("resultElement" => "users",
                    "rowElement" => "user",
                    "elements" => array(
                                "name" => "name",
                                "age" => "age",
                                "email" => "email"));

    For this output format, our expected result payload would be like,

    <users>
      <user>
         <name>xxx</name>
         <age>23</age>
         <email>xxx@xxx.xx</email>
      </user>
      <user>
         <name>yyy</name>
         <age>23</age>
         <email>yyy@yyy.yy</email>
      </user>
      ....
    </users>
  4. Define your operation using the sql query, input and output formats.
    $operations = array("getUsersByCountry" => array(
                                  "inputFormat" => $inputFormat,
                                  "sql" => $sql_query,
                                  "outputFormat" => $outputFormat));
  5. Define your database configuration in an array like this,
    $config = array(
        "db" => "mysql", // your db engine
        "username" => "myname", // name & password for the db server
        "password" => "mypasswd",
        "dbname" => "db", // the db
        "dbhost" => "localhost");
  6. Create a DataService instance using the database configuration and the operations we just created. And call DataServices reply method.
    $ds_service = new DataService(array(
                   "config" => $config,
                   "operations" => $operations));
    
    $ds_service->reply();

That is it. You just exposed your query as a web service. The PHP script URL will be the endpoint URL for the web service.

  1. WS-Addressing Action is used by web services to dispatch the operation for an incoming request SOAP message. It is one way of dispatching operations in WSF/PHP and it base Apach Axis2/C, other ways are SOAP action based dispatching which covers in my early blog “The Use of SOAP Action with WSF/PHP“,  Body based dispatching and URI based dispatching.
  2. In WSF/PHP client, we can enable the addressing by setting the “action” field in the request WSMessage instance and setting “useWSA”=> TRUE in the WSClient instance. Here is an example.
    $requestPayloadString = <<<XML
    <ns1:echoString xmlns:ns1="http://wso2.org/wsfphp/samples">
       <text>Hello World!</text>
    </ns1:echoString>
    XML;
    
    $client = new WSClient(array("to" => "http://localhost/samples/echo_service.php",
                                 "useWSA" => TRUE));
    
    $requestMessage = new WSMessage($requestPayloadString,
    	    array("action" => "http://localhost/samples/echo_service/echoString"));
    
    $responseMessage = $client->request($requestMessage);
    
    printf("Response = %s <br>", htmlspecialchars($responseMessage->str));

    If you doesn’t set “useWSA” => TRUE explicitly, the client will send the action as a SOAP action rather than a WSA Action. The above is the same example I used in demonstrating SOAP action with just the addition of “useWSA” option.

  3. You can select WS-Addressing version among “submission” which .NET support by default and “1.0″, just by mention it in the “useWSA” field.
    I.e.

    “useWSA” => “submission” Then the namespaces are having the values defined in the submission specification of WS-Addressing.
    “useWSA” => 1.0 Then the namespace are having the values defined in the WS-Addressing 1.0 spec.
  4. In the option “actions” in the WSService, we can provide the action to operation map, so the service will direct the SOAP messages to the correct operation by looking at the WS-Addressing action of the SOAP message.
    Here is a sample code that use action to dispatch the operation.

    function echoStringFunc($inMessage) {
        // logic of echoString operation
    }
    
    function echoIntFunc($inMessage) {
        // logic of echoInt operation
    }
    
    // we will take echoString and echoInt as tow operations
    $operations = array("echoString" => "echoStringFunction",
                        "echoInt" => "echoIntFunction");
    
    // soap action to operation map
    $actions = array("http://localhost/samples/echo_service/echoString" => "echoString",
                     "http://localhost/samples/echo_service/echoInt" => "echoInt");
    
    // creating the service with the operations and actions set
    $service = new WSService(array("operations" => $operations,
                                   "actions" => $actions));
    
    $service->reply();

    Note that this code is same as the code I post in a previous blog “The Use of SOAP Action with WSF/PHP” which uses SOAP action to dispatch the operation. In fact WSService will adjust to dispatch SOAP messages, so if there is a SOAP action in the message, it will be dispatched using that, and if it contains WS-Addressing action, it will used to do dispatching without the need of writing a single additional line of code. Note that this same code for both “submission” and “1.0″ WS-Addressing versions.

  5. In a WSDL 1.1, WS-Addressing action can be declared in the message element in the portType section.
        <wsdl:portType name="echoPortType">
            <wsdl:operation name="echoString">
                <wsdl:input message="ns0:echoStringRequest" wsaw:Action="http://localhost/samples/echo_service/echoString"/>
                <wsdl:output message="ns0:echoStringResponse" wsaw:Action="http://localhost/samples/echo_service/echoStringResponse"/>
            </wsdl:operation>
            <wsdl:operation name="echoInt">
                <wsdl:input message="ns0:echoIntRequest" wsaw:Action="http://localhost/samples/echo_service/echoInt"/>
                <wsdl:output message="ns0:echoIntResponse" wsaw:Action="http://localhost/samples/echo_service/echoIntResponse"/>
            </wsdl:operation>
        </wsdl:portType>

    When you use WSF/PHP in wsdl mode, it will pick the action declared in the WSDL and set it in the SOAP message, if you have enabled the addressing for the WSClient by setting non-null value for “useWSA” option.


© 2007 Dimuthu’s Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress