Few months ago, I blogged about How you represent custom headers in a WSDL. In there I mentioned, WSF/PHP is going to support sending and handling custom SOAP headers with the 2.0 release which was released early September. Today I will write how how to use this new feature in your Web Service Client.

In order to do the comparison I will show you how you could send Custom SOAP headers before WSF/PHP 2.0.

Preparing Custom SOAP Headers Manually

Before 2.0 you have to prepare the custom SOAP headers manually. For that you could use the WSHeader object.

Say you want to create the following message for your WSDL. (I excluded the headers and payload namespaces for the clarity)

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
   <soapenv:Header>
      <Header1>
         <string>test1</string>
         <int>5</int>
      </Header1>
      <Header2>
         <int>6</int>
         <string>test2</string>
      </Header2>
   </soapenv:Header>
   <soapenv:Body>
      <echo>Hello</echo>
   </soapenv:Body>
</soapenv:Envelope>

Here is how you prepare it using WSMessage and WSHeader objects.

// request payload
$requestPayloadString = <<<XML
<echo>Hello</echo>
XML;

// creation of two headers
$header1 = new WSHeader(array(
			"name" => "Header1",
			"data" => array(
				new WSHeader(array("name" => "string",
						"data" => "test1")),
				new WSHeader(array("name" => "int",
						"data" => "5")))));

$header2 = new WSHeader(array(
			"name" => "Header2",
			"data" => array(
				new WSHeader(array("name" => "int",
						"data" => "6")),
				new WSHeader(array("name" => "string",
						"data" => "test2")))));

// you prepare the soap message = request payload + two input headers
$request_msg = new WSMessage($requestPayloadString,
			array("inputHeaders" => array($header1, $header2)));

// create the WSClient with the endpoint
$client = new WSClient(array( "to" => "http://localhost/header_echo_service.php" ));

// do the request with the WSMessage instance as the request argument
$responseMessage = $client->request($request_msg);

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

As you can see you are preparing hierarchical tree of WSHeaders to prepare the SOAP message. Anyway after 2.0 you don’t need to write this much of code to get the work done.

Preparing Custom SOAP Headers in WSDL Mode

If you have a WSDL it is so easy to start by generating the initial code from the WSDL2PHP tool. If I take the WSDL from my old post about custom headers in WSDL WSDL2PHP tool will generate the following set of classes.

class Header1 {

    /**
     * @var string
     */
    public $string;

    /**
     * @var int
     */
    public $int;

}

class Header2 {

    /**
     * @var int
     */
    public $int;

    /**
     * @var string
     */
    public $string;

}

And you will get the following piece of code with the Note “TODO” where you need to fill the input fields and retrive the output values from the operation.

    // create input object and set values
    //TODO: fill $input with (data type: string) data to match your business logic

    $header_in0 = new Header1();
    // TODO: fill in the class fields of $header_in0 object which is of type Header1 to match your business logic

    $header_in1 = new Header2();
    // TODO: fill in the class fields of $header_in1 object which is of type Header2 to match your business logic

    // call the operation
    $response = $proxy->echoString($input, $header_in0, $header_in1, &$header_out0, &$header_out1);
    //TODO: Implement business logic to consume $response, which is of type string

    // TODO: Implement business logic to consume $header_out0 object, which is of type class Header1

    // TODO: Implement business logic to consume $header_out1 object, which is of type class Header2

After I follow the guidelines in the comment, My code looks so simple and little like this,

    // create input object and set values
    $input = "Hello"; // I filled $input with a string

    $header_in0 = new Header1(); // I m filling the header1
    $header_in0->string = "test1";
    $header_in0->int = 5;

    $header_in1 = new Header2(); // now the header2;
    $header_in1->string = "test2";
    $header_in1->int = 6;

    // call the operation
    $response = $proxy->echoString($input, $header_in0, $header_in1, &$header_out0, &$header_out1);

    // echoing the response payload which of type string
    echo $response;

    // echoing the $header_out0 object, which is of type class Header1
    echo "output header0 contains {$header_out0->string} and {$header_out0->int}";

    // echoing the $header_out1 object, which is of type class Header2
    echo "output header1 contains {$header_out1->string} and {$header_out1->int}";

There the headers are PHP class objects. You fill the public variables of the classes and pass them to the ‘echoString’ operation. Although it looks like it call just a php function named ‘echoString’, it actually invoke the web service operation named ‘echoString’, with the request payload and custom SOAP headers. It returns the response payload value + the output headers to the references we passed as the last 2 arguments.

So with WSF/PHP 2.0 you can use WSDL mode and WSDL2PHP tool to send payload with custom headers with a little and quick code.

Web Service can response with a Fault in 2 occasions.

  1. Fault send by the web service framework. (E.g. Invalid authentication, invalid signature found)
  2. Fault send by the user business logic.

There is a slightly difference in the content of SOAP 1.1 and SOAP 1.2. But they mainly contain the following elements.

  1. Code – A code to represent the classification of the fault. Possible fault codes can be found, http://www.w3.org/TR/soap12-part1/#faultcodes
  2. Reason – A human readable details of the reason.
  3. Details – More information about the details, mostly supposed to be read by the client application.
  4. Role – Indicates which SOAP header caused the fault. This is very rarely used in faults send from the business logic.

Sending SOAP Faults

In WSF/PHP you have the WSFault class to deal with SOAP faults. You can send a fault in your service logic by throwing an instance of WSFault class like this.

/**
 * divide mathematical operation
 * @param int $dividend
 * (maps to xs:int)
 * @param int $divisor
 * (maps to xs:int)
 * @return float $result
 * (maps to xs:float)
 */
function divide($dividend, $divisor)
{
	// dividing from 0 is invalid, we wil *throw* fault in such cases..
	if($divisor == 0) {
		throw new WSFault("Sender", "dividing from 0 is invalid");
	}

	$result = (float)$dividend/$divisor;

	return array("result" => $result);
}

Here I have throw an WSFault whenever I encounter my divisor is zero. And the WSF/PHP will take care of building the SOAP message according to the given version (default is to SOAP 1.2) and send back to the client.

Handling SOAP Faults

Similar to the service, client API also treat the SOAP fault as an instance of WSFault. So whenever you do a web service request, put inside try, catch block so you can catch exception in case of fault is received. Here is an example of handling fault while calling the divide operation in the above example.

// creating the client, we retrieved the wsdl from service url + ?wsdl
$client = new WSClient(array(
			"wsdl" => "http://localhost/myblog/fault_service.php?wsdl"));

$proxy = $client->getProxy();

try {
	// calling the operation
	$response = $proxy->divide(array("dividend" => 5, "divisor" => 0));

	// printing the result
	echo $response["result"];

} catch(Exception $e) {

	// if the instance is WSFault we print the code and the reason
	if ($e instanceof WSFault) {
        printf("Soap Fault Reason: %s\n", $e->Reason);
        printf("Soap Fault Code: %s \n", $e->Code);
	} else {
		printf("Message = %s\n",$e->getMessage());
	}
}

As you can see WSF/PHP covers the complexity of building and handling SOAP faults, Rather it gives you an API with the use of PHP Exception Construct that you already familiar with.

You can watch a Screencast on How to Consume a Web Service Using WSF/PHP from WSO2 Oxygent Tank developer portal.

There I have presented the steps you need to follow to consume a web service. I choose US National Digital Forecasting database Web Service as my example service to write the demo client.

This screencast contains,

  1. Where to find the Service documentation + WSDL and what are the information available in there.
  2. How to generate the PHP client from the WSDL using wsdlphp tool.
  3. What is in the php file generated from the wsdl2php tool and how you select the required operations to invoke.
  4. How to fill the input parameter for the web service operation
  5. How to handle the response returned from the service.
  6. Finally It shows some different ways the data that you are extracting from the service, can be presented to your user.

WSDL Caching is first introduced with the WSF/PHP 2.0.0 release to optimize the response time of PHP web services. In WSDL Caching WSF/PHP keeps an intermediate XML model which is generated from the WSDL in memory. This intermediate model which we call as ‘SIG’ or ‘Signature’ model is generated at the first request to the service. This SIG can be generated using an XSLT template from any WSDL 2.0. So if you provide a WSDL version 1.1, WSF/PHP first convert it to a WSDL 2.0 using another XSLT template and then generate the SIG model. So in generally when WSDL caching is used it avoids two XSLT parses and hence optimize the response time significantly.

In this blog, I will show you a result of some performance tests I did to measure the response time of a service with and without WSDL Caching.

The complete source codes used for the test can be found from here.

Here is a part of the service script I used. It is a simple echo service that echo a string.

	// create service in WSDL mode
	$service = new WSService(array ("wsdl" =>"echo.wsdl",
			"cacheWSDL" => false, // By default cache WSDL is true
			"actions" => $actions,
			"operations" => $operations));

	// getting the start_time
	$start_time = microtime(true);

	// process client requests and reply 
	$service->reply();

	// getting the end time
	$end_time = microtime(true);

	// getting the time difference
	$time_diff = $end_time - $start_time;

	logme($time_diff);

You can see in there I have set the “cacheWSDL” to false and log the time taken by the $service->reply() function. Later I have set the “cacheWSDL” to true and measure the time again for the comparison with earlier values.

I have written a client to invoke the service 10 times. And I’m going to measure the time taken do the client request in there.

	    for($i = 1; $i <= 10; $i ++) {
		// create client in WSDL mode
		$client = new WSClient(array ("wsdl" =>"echo.wsdl"));

		// get proxy object reference form client 
		$proxy = $client->getProxy();

		// create input object and set values
		//TODO: fill $input with (data type: string) data to match your business logic
		$input = "Hello World";

		// getting the start_time
		$start_time = microtime(true);

		// call the operation
		$response = $proxy->myEcho($input);
		//TODO: Implement business logic to consume $response, which is of type string

		// getting the end time
		$end_time = microtime(true);

		// getting the time difference
		$time_diff = $end_time - $start_time;

		logme($time_diff);

		echo $response."</br>";

	    }

Then I have measured the time taken to first 10 request for both WSDL caching on and off scenarios just after starting the Apache server.

Without WSDL Caching With WSDL Caching
WSClient Operation invocation
$client->myEcho($input)
WSService reply
$service->reply()
WSClient Operation invocation
$client->myEcho($input)
WSService reply
$service->reply()
0.11091995239258 0.074313163757324 0.15158987045288 0.11872982978821
0.082005977630615 0.06772780418396 0.046205997467041 0.035470008850098
0.082638025283813 0.072394132614136 0.044647932052612 0.028353929519653
0.079883098602295 0.06883692741394 0.037378072738647 0.026839017868042
0.082012176513672 0.068314790725708 0.046517133712769 0.035148859024048
0.074619054794312 0.063674211502075 0.041852951049805 0.027253866195679
0.084127187728882 0.071602821350098 0.041593074798584 0.027820825576782
0.081571102142334 0.066971063613892 0.057910919189453 0.038385152816772
0.087567090988159 0.073211193084717 0.043420076370239 0.02738094329834
0.078658103942871 0.064589977264404 0.050504922866821 0.037022113800049

If you obvious these values you will figure out when you don’t use WSDL caching it takes same amount of time to server each request. But when you turn on WSDL caching it takes a little more time at the very first request, but the subsequent requests take very low values.

Here is the chart for the above Data, See the Green and White lines corresponding to the WSDL caching turn on, have taken low values. In average we can observe a 50% reduction in server response time with the WSDL caching.

Response Time With and Without WSDL Caching

Response Time With and Without WSDL Caching

This result is for a very simple WSDL which only had an echo operation. When the WSDL get more complex and contain lot of wsdl/schema includes and imports, we can expect more optimization due to the WSDL caching. We will check how the complexity of the WSDL affect the performance in a later blog post.:)

In XML Schema we declare an array or a multiple occurrence of a schema element by setting its maxOccurs attribute to a value greater than 1 or to the value “unbounded” in a case of no maximum boundary.

<xs:element maxOccurs="unbounded"
            minOccurs="0"
            name="params"
            nillable="true"
            type="xs:int"/>

If you generate PHP code to such a schema using wsdl2php tool, you will get a code for the class variable named “params” similar to this.

    /**
     * @var array[0, unbounded] of int
     */
    public $params;

So if you have a variable (say $object) for the object of this class you can fill the “params” field like this,

$object->params = array(1, 5, 8);

This will create the xml with the expected array of elements.

<wrapper>
    <params>1</params>
    <params>5</params>
    <params>8</params>
</wrapper>

Not only for simple types, you can have arrays of complex types too.

<xs:element maxOccurs="unbounded"
            minOccurs="0"
            name="params"
            nillable="true"
            type="tns:MyComplexType"/>

Instead of giving simple integers like earlier case, this time you will feed the “params” variable with an array of PHP objects of ‘MyComplexType’ class.

$obj1 = new MyComplexType();
/* feeding data to obj1 variables */

$obj2 = new MyComplexType();
/* feeding data to obj2 variables */

$obj3 = new MyComplexType();
/* feeding data to obj3 variables */

$object->params = array($obj1, $obj2, $obj3);

This will create a xml containing array of params similar to this,

<wrapper>
    <params>
        <elementx/> <!-- elements in the MyComplexType type -->
        <elementy/>
    </params>
    <params>
        ... <!-- elements in the MyComplexType type -->
    </params>
    <params>
        ... <!-- elements in the MyComplexType type -->
    </params>
</wrapper>

PHP2WSDL feature of the WSF/PHP allows you to generate the WSDL for your service when you access the URL formed by adding “?wsdl” to the service URL ( or you can use service URL + “?wsdl2″ to access the wsdl version 2.0). It will generate the schema types for the wsdl from the classes you use to build the request message + the annotations you provided describing the types of the variables.

Sometime you may need to generate schema types with different names to the corresponding PHP classes. May be you need to have a ‘-’ in the schema type which is not valid in PHP class syntax or you like to have a different naming convention for PHP and wsdl.  Similarly you may need to have the operation names different in the WSDL and the PHP code.

Here is how you do it with WSF/PHP.

Different Names for Operations

/**
 * Service logic for the echo operation
 * @namespace http://ws.dimuthu.org/php/myecho/operations
 * @param object testObject $param
 * @return object testObject $return
 */
function echoMe($param) {
  return $param;
}

/* The Service operation name to PHP function name map */
$operations = array("echo" => "echoMe");

There I want my actual operation name to be echo. But I can’t declare a function name echo since PHP already has a library function echo (Yea, the one you regularly use to echo output). So I don’t have option other than declaring a function with different name (here it is “echoMe”) and mapped it in to echo operation in the operation map. We are going to feed this $operation variable at the WSService creation as its constructor argument.

Lets see how different names are used in schema types and corresponding php class names.

Different names for Types and Classes

/**
 * @namespace http://ws.dimuthu.org/php/myecho/types
 */
class testObject {

	/**
	 * @var integer aint
	 */
	public $aint;

	/**
	 * @var string astring
	 */
	public $astring;
}

/* The mapping of schema types to PHP class */
$classmap = array("test-object" => "testObject");

It is similar how we mapped operation in the previous section. Just use $classmap variable which map the schema type name to the php class name.

Here is the type section and the interface section of the WSDL 2.0 generated using above codes. Observe the operation names and the types names are formed the way we expected.

  <types>
    <xsd:schema xmlns:ns0="http://ws.dimuthu.org/php/myecho/types"
        xmlns:ns1="http://ws.dimuthu.org/php/myecho/types"
        elementFormDefault="qualified"
        targetNamespace="http://ws.dimuthu.org/php/myecho/operations/xsd">
      <xsd:import namespace="http://ws.dimuthu.org/php/myecho/types"/>
      <xsd:element name="param" type="ns0:test-object"/>
      <xsd:element name="return" type="ns1:test-object"/>
    </xsd:schema>
    <xsd:schema elementFormDefault="qualified"
                targetNamespace="http://ws.dimuthu.org/php/myecho/types">
      <xsd:complexType name="test-object">
        <xsd:sequence>
          <xsd:element name="aint" type="xsd:integer"/>
          <xsd:element name="astring" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </types>
  <interface name="myEchoPortType">
    <operation name="echo" pattern="http://www.w3.org/ns/wsdl/in-out">
      <input element="tnx:param"/>
      <output element="tnx:return"/>
    </operation>
  </interface>

Here is the complete code (Combining all the previously mentioned code segments). You can check the complete wsdl generation (wsdl  1.1 or wsdl 2.0 as your preference) by copying and pasting this code to the online php2wsdl generator at the WSF/PHP Demo Site.

<?php

/**
 * Service logic for the echo operation
 * @namespace http://ws.dimuthu.org/php/myecho/operations
 * @param object testObject $param
 * @return object testObject $return
 */
function echoMe($param) {
  return $param;
}

/**
 * @namespace http://ws.dimuthu.org/php/myecho/types
 */
class testObject {

	/**
	 * @var integer aint
	 */
	public $aint;

	/**
	 * @var string astring
	 */
	public $astring;
}

/* The Service operation name to PHP function name map */
$operations = array("echo" => "echoMe");

/* Telling that we input MIX types for the parameters */
$opParams = array("echo" => "MIXED");

/* The mapping of schema types to PHP class */
$classmap = array("test-object" => "testObject");

/* Creating the WSService and serving the Request */
$service = new WSService(array(
			"operations" => $operations,
			"classmap" => $classmap,
			"opParams" => $opParams,
			"serviceName" => "myEcho"));

$service->reply();

?>

If you are thinking of writing a web service or a client based on a WSDL, you can easily generate the code for PHP or any other language using tools likes wsdl2php or other wsdl2xxx category tools. Then you don’t need to really worry about what is the schema of the WSDL or any other finer details. But sometime it may useful to know how different schema constructs are generated in PHP level so you can have a good idea when you are using them. This post describes How inheritance is used in XML Schema and how it is mapped to PHP code from wsdl2php tool in WSF/PHP.

There are several ways that one schema type can inherit another type.  Here are some names use to refer them.

  • SimpleType Restriction – Forming simple type by restricting another simple type
  • SimpleContent Extension – Forming complex type by extending a simple type
  • ComplexContent Extension – Forming complex type by extending another complex type

Note that here the word ‘type’ always refers to a schema type.

It is not straight forward to do a one to one map from these schema structures to a PHP or some other language. But wsdl2php tool does that keeping the simplicity and preserving the original meaning. Lets see how it is done for each of the above mentioned methods of inheriting.

SimpleType Restriction

You can create a simple type by restricting some values of another simple type. Here is an example.

            <!-- derivedType from applying
              simple type restriction for xs:string -->
            <xs:simpleType name="derivedType">
                <xs:restriction base="xs:string">
                    <xs:enumeration value="a"/>
                    <xs:enumeration value="ab"/>
                    <xs:enumeration value="abc"/>
                    <xs:enumeration value="abcd"/>
                </xs:restriction>
            </xs:simpleType>

Here the derivedType is a string, but it can only have values “a”, “ab”, “abc” and “abcd”. This restriction have used the “enumeration” (which we call a facet) to restrict the possible values. You can use other facets like length, minLength, MaxLength and so on. Here are the complete list of facets in the schema specification.

So lets see hows this is mapped to a PHP code. Here we assume this type is used in an schema element called ‘input’.

    /**
     * @var string
     *     NOTE: $input should follow the following restrictions
     *     You can have one of the following value
     *     a
     *     ab
     *     abc
     *     abcd
     */
     public $input;

Note that here it does not say anything about the ‘derivedType’. Rather it says it is of type “String” which is a PHP type and in addition it has some restrictions, or rules when assigning values.

Although it could have been possible to use getters and setters to impose these rules, this uses just a comment about the rules because this way it is really easy the use the variable.

Say we have another type (say derievedType2) restricting the ‘derievedType’, that type will have the combination of restrictions of both types.

Here is the xml schema representation of the ‘derievedType2′.

            <!-- derivedType2-->
            <xs:simpleType name="derivedType2">
                <xs:restriction base="tns:derivedType">
                    <xs:maxLength value="3"/>
                    <xs:minLength value="2"/>
                </xs:restriction>
            </xs:simpleType>

And if input2 have that type, the php code will look like this, (Note that it has the combination of rules).

    /**
     * @var string
     *     NOTE: $input2 should follow the following restrictions
     *     You can have one of the following value
     *     a
     *     ab
     *     abc
     *     abcd
     *     Your length of the value should be
     *     Greater than 2
     *     Less than 3
     */
     public $input2;

I have highlighted the additional rules compared with $input, so you can see the difference.

SimpleContent Extension

Simple Content extension is extending a simple type to make a complex type. Say we have an element (say with the name “mystring”) and it has “xs:string” simple type.

<xs:element name="mystring" type="xs:string"/>

And here is a valid xml with this schema.

<mystring>this can contain only string</mystring>

So if I say I’m going to make a complex type extending this simple type you may think that I’m going to add element in to that. In fact I will create a complex type by adding an attribute.

<mystring myint="3">this can contain only string</mystring>

The schema to this xml will be something like this. (Note that I have assumed there is an schema element named “mystring” with the type “myStringType”)

            <xs:complexType name="myStringType">
                <xs:simpleContent>
                    <xs:extension base="xs:string">
                        <xs:attribute name="myint" type="xs:int"/>
                    </xs:extension>
                </xs:simpleContent>
            </xs:complexType>

The PHP generated code for this schema is something like this,

class myStringType {

    /**
     * @var int
     */
    public $myint;

    // The "value" represents the element 'myStringType' value..

    /**
     * @var string
     */
    public $value;

}

So as you can see it creates a PHP class for that schema type with member variables for each attributes and finally for the value of the parent type. So in order to represent the above mentioned xml, you will use the following PHP code.

$type = new myStringType();

$type->myint = 3;
$type->value = "this can contain only string";

Next we will look at the inheritance with complexContent Extension.

ComplexContent Extension

This is to create a complex type by inheriting another complexType.

            <!-- the parent type -->
            <xs:complexType name="parentType">
                <xs:sequence>
                    <xs:element name="demo3" type="xs:int"/>
                    <xs:element name="demo4" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>

            <!-- the child type -->
            <xs:complexType name="childType">
                <xs:complexContent>
                    <xs:extension base="tns:parentType">
                        <xs:sequence>
                            <xs:element name="demo1" type="xs:int"/>
                            <xs:element name="demo2" type="xs:string"/>
                        </xs:sequence>
                    </xs:extension>
                </xs:complexContent>
            </xs:complexType>

So here the childType will inherit the ‘demo3′ and ‘demo4′ elements from the parent type. We will see how is the PHP generated code looks like.

class parentType {

    /**
     * @var int
     */
    public $demo3;

    /**
     * @var string
     */
    public $demo4;

}

class childType extends parentType {

    /**
     * @var int
     */
    public $demo1;

    /**
     * @var string
     */
    public $demo2;

}

It has uses the PHP inheritance to reprensent the schema inheritance. And the nice thing is you can use the childType for the places you have to use the parentType.  That is the theoy we learn at the inheritance class of other languages (Java, C++) too.

So say there is another complexType (say “anotherChildType”) inheriting from the type “parentType” and one another complexType (say “nextLevelChildType”) inheriting this time from “childType” (which in fact inheriting from the “parentType” as mentioned above).

So our types tree would be something like this.

--- parentType
         |
         +-------- childType
         |              |
         |              +------------- nexLevelChildType
         |
         +-------- anotherChildType

And lets say there is a schema element called ‘input3′ with the type parentType. Then the generated variable for the input3 element will be like following code segment.

    /**
     * @var (object)parentType
     *    Or one of following derived class(es)
     *       childType
     *       nextLevelChildType
     *       anotherChildType
     */
    public $input3;

This comment tells you that you can actually use the inherited types in place of the parent type according to your preferences.

WSF/PHP Demo Site contains number of applications that demonstrate the different features of WSO2 WSF/PHP in practice. Calendar Service is one of such application. It demonstrate the use of WSDL Mode for a service with different policies for different operations + the use of Username tokens.

You can view the source code of the Calendar Service from here.

The username token is provided as an arguments to the WSService constructor at the end of the service script.

// our security token
$security_token = new WSSecurityToken(array("passwordCallback" => "get_password",
                                      "passwordType" => "plain"));
// create service in WSDL mode
$service = new WSService(array ("wsdl" =>"Calendar.wsdl",
        "actions" => $actions,
        "classmap" => $class_map,
        "securityToken" => $security_token,
        "operations" => $operations));

// process client requests and reply 
$service->reply();

We use a callback function (“get_password”) to validate the user and give that function name to the securityToken object constructor. Inside that callback function, we retrieve the password for the user from a database call. Here is the code inside the callback function that is again extracted out from the calendar service.

/**
 * call back function.
 * verify the validity of user enterd password with
 * the actual password which is kept in the database.
 */
$current_username = "";
function get_password($username)
{

    $dbhost = DB_HOST;
    $dbname = DB_NAME;
    $dbuname = DB_USERNAME;
    $dbpass = DB_PASSWORD;
    $link=mysql_connect($dbhost,  $dbuname,  $dbpass);
    mysql_select_db($dbname, $link);

    $sql="SELECT password FROM `customer_details` WHERE `user_name` = '".$username."'";
    $result=mysql_query($sql,$link);
    $password=mysql_fetch_array($result, MYSQL_NUM);

    global $current_username;
    if($password) {
         $current_username = $username;
         return $password[0];
    }
    else {
         $current_username = "";
         return NULL;
    }
}

So for all the operations which require authentication like login, getEvents, deleteEvents and addEvent, the WSF/PHP engine validate the user before invoking the operation. If the authentication fails, the engine will send a SOAP fault with the fault details. But in this service there is a operation which doesn’t require authentication. That is the ‘register’ operation. Because until the registration complete you can’t have a username password, so we should not authenticate that ‘register’ operation. So we need to provide a different policy for the ‘register’ operation.

The policies for each of the operation is declared in the Calender.wsdl itself.  If you look at the WSDL you can see each of the policies required by the operations are declared inside the policy elements as mentioned in WS-Policy Specification. And each of the operation refers the corresponding policy element from the binding section of the WSDL.

You can see how it is done for login (which requires authentication) and the register (which doesn’t requires authentication) from the code below.

        <wsdl:operation name="login">
            <soap12:operation soapAction="urn:login" style="document"/>
            <wsdl:input>
                <wsp:PolicyReference URI="#username_token_policy"/>
                <soap12:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap12:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="register">
            <soap12:operation soapAction="urn:register" style="document"/>
            <wsdl:input>
                <soap12:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap12:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>

In WSF/PHP WDL Mode we have two APIs, first one is the class based API which we give a class object as the input parameter for the operation and expect to retrieve a class object as the response as well. The other API is the array based API. which we give an array (in fact an associated map) containing all the necessary information and returns an array filled with response information.

If you are using WSDL2PHP script you are always using the class based API. But there are situations where you can easily use array based API instead of the class based API. Here is an example.

Take the simple add operation of the following WSDL, http://labs.wso2.org/wsf/php/example.xml.

If you generated the code using wsdlphp tool (Here is the complete generated code for the above wsdl using online wsdlphp tool) You can see two classes are generated for the above operation, one for the input object and the other for the output object.

class simpleAdd {

    /**
     * @var int
     */
    public $param0;

    /**
     * @var int
     */
    public $param1;

}

class simpleAddResponse {

    /**
     * @var int
     */
    public $return;

}

So in order to invoke the service you need to create an object of the simpleAdd and set your input parameters and return the value from the simpleAddResponse object.

  $input = new simpleAdd();

  $input->param0 = 3;
  $input->parma1 = 4;

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

  // extract the return value
  echo $response->return;

But if you are using array mode for the same operation it will be something like this.

  // input as an array
  $input = array("param0" => 3, "param1" => 4);

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

  // extract out the return value from the array
  echo $response["return"];

In this approach you don’t need to declare classes at the start. So you can write the code without the support of WSDL2PHP tool. Anyway for complex scenarios it is not easy to find the keys needed to be in the input array, so it is better depend on the generated code. But you can use array based approach more productively for simple scenarios like this.

PHP in most percentage is used with MySQL Server in LAMP or WAMP stacks. But there may be situations where PHP uses MSSQL databases in back-end. And PHP scripts can be used to make Web services exposing MSSQL Databases. That is enabled by the  Data Services capability in WSF/PHP 2.0.0.

Here are the steps to get the PHP Data Services working with MSSQL in windows. You can safelty skip the starting point if you have already have the necessory software installed.

  • Download Apache Web Server, PHP and MSSQL server. (You can download the MSSQL server 2005 expess edition from here.
  • Enable the php_mssql, php_pdo and php_pdo_mssql extension from the php.ini.
  • If you have MSSQL server 2005, the default client DLL (ntwdblib.dll) use to connect to MSSQL server will not work. So you need to download a newer version of this dll. You can easily find this googling the name of the dll. (The dll version worked for me is 2000.80.194.0). Copy this dll to following directories.
    • <your_windows_drive>/windows/system32
    • <your_apache_installation>/apache2/bin
  • To Demo purpose I have created a MSSQL database called “RESTFulSchool” and and table called ‘Subjects” with the following schema. If you already have a MSSQL database you can just continue with that.
    Column Name Data Type
    subjectID int
    subjectName text
    subjectTeacher text

    And make sure you fill some data into the table. You can get this done easily with MSSQL Server Management Studio downloadable from http://www.microsoft.com/sql/editions/express/default.mspx

  • So here is my code to the Data Service. Note in the config variable I have given the information about my MSSQL connection.
    <?php
    
    //Including the Data Services library
    require_once("wso2/DataServices/DataService.php");
    
    //Including the connection information for my MSSQL Connection
    require_once("constants.php");
    
    // database configurations
    $config = array(
    		"db" => "mssql",
    		"username" => MSSQL_USERNAME
    		"password" => MSSQL_PASSWORD
    		"dbname" => "RESTfulSchool",
    		"dbhost" => MSSSQL_SERVER_NAME
    		);
    
    $output_format = array(
                        "resultElement" => "subjects",
                        "rowElement" => "subject",
                        "elements" => array(
                                "name" => "subjectName",
                                "teacher" => "subjectTeacher"));
    
    $sql = "SELECT subjectName, subjectTeacher FROM Subjects";
    
    $get_subjects_op = array("outputFormat" => $output_format, "sql" => $sql);
    
    $get_subjects_url = array("HTTPMethod" => "GET", "RESTLocation" => "subjects");
    
    // list of operations
    $operations = array(
                    "getSubjects" => $get_subjects_op,
                    );
    
    // list of rest url mappping (operation => url)
    $restmap = array(
                    "getSubjects" => $get_subjects_url,
                    );
    
    // creating DSService and reply
    $service = new DataService(array("config" => $config, "operations" => $operations, "RESTMapping"=>$restmap));
    $service->reply();
    
    ?>
  • You just wrote a SOAP+REST Data Service to expose your MSSQL Data as a Web Service. Now Put this script (say school_service.php) in to the Apache web directory and access it using a browser with the following url.
    http://localhost//school_service.php/subjects

    If you have done every thing right, you should see a nice xml showing your data. Note that here we used REST interface to test our service. You don’t need to do any thing special to expose it as SOAP. Its SOAP endpoint would be simply

    http://localhost//school_service.php

Get the WSDL Generation working with MSSQL
If you try to retrieve the WSDL for the above service using this URL

http://localhost//school_service.php?wsdl

You will get an error message saying that the meta data retrieval is not supported for this particular driver (MSSQL Driver). For the time being, in order to get rid of this warning you have to disable showing warnings in your PHP programs. You can get it done by editing the php.ini with this entry

error_reporting = E_ALL & ~E_NOTICE & ~E_WARNING

But even with this fix, the schema types of the name and teacher entries will be shown as “xsd:anyType”. If you want to have a more specific type associated with them, Just change the $output_format variable to the following.

$output_format = array(
                    "resultElement" => "subjects",
                    "rowElement" => "subject",
		    "elements" => array(
			"name" => array("column" => "subjectName", "xsdType" => "xsd:string"),
			"teacher" => array("column" => "subjectTeacher", "xsdType" => "xsd:string")));

Here instead of giving a string to ‘teacher’ and ‘name’ entries, we give an array containing both column name and the the custom xsd type we want to appear in the WSDL.  Note that this fix is needed only for databases that doesn’t provide the meta data interface through the PHP PDO layer. For database like mysql wsdl generation works straight away.


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