2007/04/05
5 Apr, 2007

PHP SOAP Extension

  • Samisa Abeysinghe
  • VP, Training - WSO2


Introduction

A PHP SOAP Extension can be used to provide and consume Web services. In other words, this PHP extension can be used by PHP developers to write their own Web Services, as well as to write clients to make use of the existing Web services.
The SOAP extension that comes with PHP 5 is an attempt to implement the Web services stack support for PHP. Unlike most other efforts to support Web services for PHP, the SOAP extension is written in C. Hence it has the advantage of speed, over the other extensions.

The SOAP extension supports the following specifications. If not whole, at least the required subset for basic Web services.

  • SOAP 1.1
  • SOAP 1.2
  • WSDL 1.1

The SOAP extension mainly focuses on RPC style Web services. However, you can also use document literal style WSDL files with the WSDL mode of services and clients.

This extension uses GNOME XML library for XML processing.

Classes of the Extension

There are six classes implemented by this extension. Three of the classes are high level classes with useful methods. These classes are SoapClient, SoapServer, and SoapFault. The other three classes are low level and do not have any methods other than their constructors. These low level classes are SoapHeader, SoapParam, and SoapVar.

SOAP extension class structure

SoapClient Class

This class can be used to consume Web services. The SoapClient acts as a client for a given Web service.
It has two modes of operation:

  • WSDL mode
  • Non-WSDL mode

In the WSDL mode, the constructor will take in a WSDL file name as a parameter and extract information about the service to be consumed from the WSDL.
In the non-WSDL mode, options can be used to convey the information to be consumed. This class comes with several methods that are useful in consuming services. Out of them, SoapClient::__soapCall() is the most important. This method can be used to call an operation on a service.

SoapServer Class

This class can be used for providing Web services. The SoapServer acts as a Web service. Like SoapClient, the SoapServer too has two modes of operation: the WSDL mode and the non-WSDL mode. The two modes have similar meanings to those of SoapClient. In the WSDL mode, the service implements the interface given by the WSDL, and in the non-WSDL mode, options can be used to govern the service behavior.
Out of the methods in the SoapServer class, three methods are most important. They are SoapServer::setClass(), SoapServer::addFunction() and SoapServer::handle().

The SoapServer::setClass() method sets the class to be used as the implementation of the Web service. All the public methods of the class set with SoapServer::setClass become the operations of the Web service.

The SoapServer::addFunction() method can be used to add one or more functions that can act as the operations of the Web service.

The SoapServer::handle() method instructs the Web service script to start processing the incoming request. A Web service script is a PHP script with one or more SoapServer object instances. Although you can have more than one SoapServer object, the common practice is to have just one SoapServer instance per script. The Web service script would use whatever information that is set up on a SoapServer object instance, prior to the call to the SoapServer::handle() method, when processing the incoming request and preparing the outgoing response.

SoapFault Class

This class is inherited from the Exception class and can be used when dealing with errors. SoapFault instances can be thrown or caught with SOAP fault related information and be dealt with as required by the programmer.

SoapHeader Class

This class can be used to represent SOAP headers. It is just a data container and does not have any methods other than the constructor.

SoapParam Class

The SoapParam class too is just a data container with only the constructor method. This class can be used to represent the parameters passed to Web service operations. This class is useful in the non-WSDL mode to convey information in the expected format of parameters.

SoapVar Class

SoapVar is also a low level class with only a constructor, like the SoapHeader and SoapParam classes. This class can be used for encoding parameters passed to an operation of a Web service. This class is useful in the non-WSDL mode to convey type information.

WSDL vs. non-WSDL Modes

In Web services, there are two models of implementation: Contract First model and Code First model.

In the contract first model, a WSDL file, which is an XML file that defines the service interface, is used. The WSDL file defines the interface that the service has to implement or the client has to consume. The WSDL mode of the SoapServer and SoapClient is based on this concept.

In the code first model, the code implementing the service is written first. Then in most cases a contract, in other words a WSDL, is generated out of the code. Then the client can use that WSDL, at the time of consuming the service, to take note of the interface of the service. However, the PHP 5's SOAP extension does not have provisions for generating a WSDL out of the code. To cater for this situation, the non-WSDL mode of the SoapServer and SoapClient can be used.

Hello World with the SOAP Extension

This section explains how to implement services and clients both in the WSDL and non-WSDL modes. Comparatively, it is easier to implement services and clients in the WSDL mode, given that a WSDL is available with the desired interface. Hence this section will first describe how to implement a Web service using the WSDL mode.

In the sample Hello World service, there is an operation named greet. This operation takes a name as a string and returns a greeting as a string. This sample uses the following WSDL:

 

<wsdl:definitions 
xmlns:impl='https://wso2.org/wsf/php/helloService'
xmlns:intf='https://wso2.org/wsf/php/helloService'
xmlns:wsdl='https://schemas.xmlsoap.org/wsdl/'
xmlns:wsdlsoap='https://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='https://www.w3.org/2001/XMLSchema'
targetNamespace='https://wso2.org/wsf/php/helloService'>
<wsdl:types>
<schema elementFormDefault='qualified'
xmlns:impl='https://wso2.org/wsf/php/helloService'
xmlns:intf='https://wso2.org/wsf/php/helloService'
xmlns:wsdl='https://schemas.xmlsoap.org/wsdl/'
xmlns="https://www.w3.org/2001/XMLSchema"
targetNamespace='https://wso2.org/wsf/php/helloService' >
<element name='greet'>
<complexType>
<sequence>
<element name='name' type='xsd:string' />
</sequence>
</complexType>
</element>
<element name='greetResponse'>
<complexType>
<sequence>
<element name='greetReturn' type='xsd:string' />
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>
<wsdl:message name='greetRequest'>
<wsdl:part name='parameters' element='impl:greet' />
</wsdl:message>
<wsdl:message name='greetResponse'>
<wsdl:part name='parameters' element='impl:greetResponse' />
</wsdl:message>
<wsdl:portType name='helloService'>
<wsdl:operation name='greet'>
<wsdl:input name='greetRequest' message='impl:greetRequest' />
<wsdl:output name='greetResponse' message='impl:greetResponse' />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name='helloServiceSoapBinding' type='impl:helloService'>
<wsdlsoap:binding transport='https://schemas.xmlsoap.org/soap/http' style='document' />
<wsdl:operation name='greet'>
<wsdlsoap:operation soapAction='helloService#greet' />
<wsdl:input name='greetRequest'>
<wsdlsoap:body use='literal' />
</wsdl:input>
<wsdl:output name='greetResponse'>
<wsdlsoap:body use='literal' />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name='helloService'>
<wsdl:port binding='impl:helloServiceSoapBinding' name='helloService'>
<wsdlsoap:address location='https://localhost/hello/hello_service_wsdl.php' />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

WSDL Mode Service

Here is the source for the WSDL mode service using the SOAP extensionAPI.

<?php 
function greet($param) {
$retval = 'Hello '.$param->name;
$result = array('greetReturn' => $retval);
return $result;
}

$server = new SoapServer('hello.wsdl');
$server->addFunction('greet');
$server->handle();
?>

In the service implementation, the function implementing the greet operation, as defined by the WSDL to be used for the service, appears first. The greet operation takes a single parameter as specified by the WSDL. As per the semantics of the greet operation, the implementation expects that parameter to be the first name of the user. The function returns a hello greeting adding 'Hello' in front of the parameter given.

After defining the function, a SoapServer object is created, passing the name of the WSDL file to be used for the service. Then the greet function is added to the service, indicating the name of the function implementing the greet operation. Finally, the handle is called on the service object, which triggers the processing of the incoming request.

WSDL Mode Client

Source code for the client is shown below.

<?php

try {
$client = new SoapClient('hello.wsdl');
$result = $client->__soapCall('greet', array(array('name' => 'Sam')));
printf("Result = %s\n", $result->greetReturn);

} catch (Exception $e) {
printf("Message = %s\n",$e->__toString());
}
?>

In the client code, first the SoapClient instance is created with the name of the WSDL to be used. Next the operation to be invoked on the service is called with the __soapCall() method giving the name of the operation, in this case 'greet' and the parameters to be passed to the operation. In line with the WSDL being used, the greetReturn data member of the returned result struct will hold the greeting returned by the service.

Request and Response

When you place the above PHP scripts in the document root of your Webserver, and request the client script from a Web browser or invoke the scriptusing the command line PHP interpreter, the client will send a SOAP requestto the service script and the service will respond to the client with a SOAPresponse.

Following is the SOAP request that is sent by the client:

   <?xml version="1.0" encoding="UTF-8"?>   
<SOAP-ENV:Envelope xmlns:SOAP-ENV="https://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="https://wso2.org/wsf/php/helloService">

<SOAP-ENV:Body>
<ns1:greet>
<ns1:name>Sam</ns1:name>
</ns1:greet>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Following is the SOAP response that is sent by the service in response to the above request:

   <?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="https://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="https://wso2.org/wsf/php/helloService">
<SOAP-ENV:Body>
<ns1:greetResponse>
<ns1:greetReturn>Hello Sam</ns1:greetReturn>
</ns1:greetResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The above SOAP messages were captured using the WSDL mode client and service. It is possible to implement the service and client using the non-WSDL mode to generate the same SOAP messages. However, the PHP code that has to be written changes slightly. The following sections explain how to use the non-WSDL mode.

non-WSDL Mode Service

<?php function greet($param) {    

$retval = 'Hello '.$param;
return new SoapParam($retval, 'greetReturn');

}

 
$server = new SoapServer(null, array('uri' => 'https://wso2.org/wsf/php/helloService'));

$server->addFunction('greet');
$server->handle();
?>

In the non-WSDL mode, as in the case of the WSDL mode, the greet function is implemented first. However, the way the function is implemented is a bit different to how it is done in the WSDL mode. Rather than just returning an array representing the response, in the non-WSDL mode we have to wrap the return value with a SoapParam object. When creating the service, the first parameter is null as no WSDL is provided; instead an options array is passed. The only mandatory option is the URI of the service. The rest of the method calls are similar to those called in the WSDL mode.

non-WSDL Mode Client

<?php try {    

$client = new SoapClient(null,
array('location' => 'https://localhost/hello/hello_service_nonwsdl.php',
'uri' => 'https://wso2.org/wsf/php/helloService'));
$result
= $client->__soapCall('greet', array(new SoapParam('Sam', 'name'))); printf("Result = %s\n", $result);

} catch (Exception $e) {
printf("Message = %s\n",$e->__toString());
}
?>

In the non-WSDL mode, because a WSDL is not being used, an options array is passed with the mandatory options of the location and the URI. The call to __soapCall() method is similar to that used in the WSDL mode. However, the SoapParam class is used to wrap the parameters in the expected format. The returned result will capture the greeting in the response.

Conclusion

This article introduced the SOAP extension that can be useful in providing and consuming Web services using PHP. The key strengths of the PHP extension include its simplicity and speed. It is quite simple to get a service and client up and running with the SOAP extension implemented in C. While the SOAP extension can be very useful when dealing with simple Web services, there are limitations when considering the full Web services stack. WSO2 WSF/PHP is intended to fill some of the gaps in the PHP extension. WSO2 WSF/PHP is an open source implementation like the SOAP extension and supports MTOM, WS-Addressing, WS-Security, and WS-RelaiableMessaging. WSO2 WSF/PHP supports a similar API to that of the SOAP extension. There are plans to wrap the API to provide the same API of the SOAP extension; it will be written in C.

Author

Samisa Abeysinghe, Software Architect, WSO2 Inc. samisa at wso2 dot com

 

About Author

  • Samisa Abeysinghe
  • VP, Training
  • WSO2 Inc.