Arsenalist

The Toronto Raptors Blog with an Arsenal touch

Writing PHP clients for XFire, Axis and .NET Web Services

Posted by Arsenalist on January 19, 2007

If you’re finding yourself hunting down incomplete documentation about writing a PHP client for your Java or .NET web services, you’re not alone. PHP SOAP toolkits like NuSOAP and Pear SOAP provide sub-par API’s into web service development and give a decent person a really hard time when it comes to writing clients. The best way to go IMHO is using PHP’s built-in SOAP libraries. The other thing to keep your eye on is Axis2 for PHP which is still in Beta. For now we’ll focus on the PHP 5 and it’s SOAP extension. To enable the extension, your php.ini file must something like the following:

Under Dynamic Extensions:

extension_dir="C:/php/ext/"
extension=php_soap.dll

Under Module Settings:

[soap]
soap.wsdl_cache_enabled=0
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400

Restart the Apache Web Server for the changes to take effect, once that is done, we are free to use the PHP Soap extensions. This example is applicable to Java web services generated by XFire or Axis or any other framework and also to .NET web services. As long as there’s a WSDL, we’re good. This example has been tested with XFire 1.2.4.

In this example there is one web service called SportsService which exposes one method: public Mascot getMascot(Team team)

The method takes in as parameter a complex Java object called Team and returns a Mascot, another complex data type. Although this example can easily use primitives, I’ve chosen to use Java objects because I want to illustrate a specific point. The XFire Java client is fairly easy to write and a previous blog entry covered a similar client. Both the Team and Mascot classes are POJO’s with one String property called name, a default constructor and getter/setter methods. They are excluded here for brevity.

Before we look at the PHP client, let’s look at the relevant portion of the WSDL that is generated, mainly the types and the information about the method getMascot which we will be calling:

<wsdl:types>
    <xsd:schema
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified"
            elementFormDefault="qualified"
            targetNamespace="http://vo.arsenalist.com">
        <xsd:complexType name="Team">
            <xsd:sequence>
                <xsd:element minOccurs="0"
                             name="name"
                             nillable="true"
                             type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
        <xsd:complexType name="Mascot">
            <xsd:sequence>
                <xsd:element minOccurs="0"
                             name="name"
                             nillable="true"
                             type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:schema>
    <xsd:schema
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified"
            elementFormDefault="qualified"
            targetNamespace="http://ws.arsenalist.com">
        <xsd:element name="getMascot">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element maxOccurs="1"
                                 minOccurs="1"
                                 name="team"
                                 nillable="true"
                                 type="ns1:Team"/>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
        <xsd:element name="getMascotResponse">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element maxOccurs="1"
                                 minOccurs="1"
                                 name="out"
                                 nillable="true"
                                 type="ns1:Mascot"/>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
    </xsd:schema>
</wsdl:types>

Here’s the PHP client that creates a Team type, passes it to the web service which returns a Mascot type.

<?php

//set up the service client using WSDL
$wsdl = "http://arsenalist.com/SportsService?wsdl";
$client = new SoapClient($wsdl);

// assign the name attribute of Team to "toronto"
$wrapper->team->name =
		new SoapVar("toronto", XSD_STRING);

// call the getMascot method
$response = $client->__soapCall("getMascot",
				    array($wrapper));

// print out the Mascot
print($response->out->name);

?>

The wrapper object is created out of the blue so as to pass it to the web service as the lone parameter encapsulating the Team data type.

By looking at the WSDL, we can determine how to “instantiate” Team and Mascot data types on the client side. For example, to create a Team data type and assign it’s name property to “toronto”, we simply refer to it using associative array syntax and both the Team object and it’s property name are created “on the fly”. There’s no mucking around with namespaces etc. We’re simply wrapping the primitives inside other PHP “objects” using the same syntax as associative arrays. You can go as deep as you want in the object hierarchy in PHP without having to worry about encountering nulls because if an array element being accessed doesn’t exist, it is created for you.

It’s also always a good idea to use the $client->__getTypes() and do a print_r(..) on the results to see what you are dealing with before you start communicating with a WSDL For example, the result of a print_r($client->__getTypes()) on the above WSDL returned the following:

Array (
   [0] => struct Team { string name; }
   [1] => struct Mascot { string name; }
   [2] => struct getMascot { Team team; }
   [3] => struct getMascotResponse { Mascot out; }
)

As you can see this information can be helpful when deciding how to initialize your client side variables.

Note that you can also use $client->getMascot($wrapper) instead of $client->__soapCall(“getMascot”, array($wrapper)). The latter is used mostly when passing extra parameters such as SOAP headers etc.

This is a fairly simple example which hopefully illustrated the point that accessing web services using PHP is not a daunting task, and most of all there are no additional libraries to install as long as you’re using PHP5 and up.  If you would like write a PHP client that accesses a WS-Security enabled service, you should read Kim Cameron’s IdentityBlog entry which has links to the source code needed.

Advertisements

2 Responses to “Writing PHP clients for XFire, Axis and .NET Web Services”

  1. Dohtar said

    Very nice point of interests. I was looking the net just for this purpose. Needing exactly the function $client->__getTypes() I hope i will be able to use it.

    If someone has any idea of how to exctract elements data from “example.wsdl” which was originally written in java i would be very gratefull. To be exact:i have an wsdl describin web service written in java and inside are some complex types that i have construct in PHP. Have anyone any idea og how to achieve this, preferable with an automated process or application??

  2. […] method involves modifying the generated code which is highly undesirable. Using the very simple SportsService web service example, you must modify the generated SportsService_client.py and edit the following […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: