the previous article in this series I demonstrated how XML is used to
make remote procedure calls with XML-RPC in PHP. This article will
focus on SOAP and WSDL (both of which use XML as their underlaying
method of describing data) and demonstrate how a PHP script can act as
a SOAP client and auto-magically discover detailed information about a
web service.
originally an acronym for Simple Object Access Protocol, is a
lightweight XML-based messaging protocol designed to work in a
distributed environment. It provides a foundation layer which can
be built upon to facilitate complex messaging among web services. SOAP
messages are encoded using XML and XML-RPC messages, and they are
often sent over an HTTP connection. A simple SOAP envelope (message)
that asks for the time may look like this:
<?xml version="1.0" encoding="UTF-8" ?>
<soap:Envelope xmlns:soap="http://shcemas.xmlsoap.org/soap/envelope/" >
<soap:Body>
<getTime xmlns="https://phpbuilder.com/adam_delves/fourth_dimension/">
<timeZone>London/Europe</timeZone>
</getTime>
</soap:Body>
</soap:Envelope>
makes use of XML name spaces. The URI by convention should link to a
schema document defining the name space. The soap name space contains
the soap envelope and the default name space used in the getTime
element contains the message. The response might look as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<soap:Envelope xmlns:soap="http://shcemas.xmlsoap.org/soap/envelope/" >
<soap:Body>
<getTimeResponse xmlns="https://phpbuilder.com/columns/adam_delves/fourth_dimension/">
<time>
<hour>12</hour>
<minute>34</minute>
<second>10</second>
</time>
<format>24h</format>
</getTimeResponse>
</soap:Body>
</soap:Envelope>
of the applications of SOAP is to describe the message patterns of RPC
calls and responses between web services. The format of an RPC call
contained in a SOAP envelope is slightly different and more complex
than an XML-RPC message. However, its complexity allows for scalability
in describing more complex service structures and data types.
<?xml version="1.0" encoding="UTF-8" ?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s-enc="http://schemas.xmlsoap.org/soap/encoding/"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding" >
<soap:Body>
<verify xmlns="https://phpbuilder.com/columns/adam_delves/email_validator.verify/">
<symbol xsi:type="xsd:integer">54</symbol>
<symbol xsi:type="xsd:string">RG5H4</symbol>
</verify>
</soap:Body>
</soap:Envelope>
<?xml version="1.0" encoding="UTF-8" ?>
<soap:Envelope
xmlns:soap="http://shcemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s-enc="http://schemas.xmlsoap.org/soap/encoding/"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding" >
<soap:Body>
<verifyResponse xmlns="urn:webservices-email_validator">
<Result xsi:type="xsd:boolean">false</Reponse>
</verifyResponse>
</soap:Body>
</soap:Envelope>
- http://shcemas.xmlsoap.org/soap/envelope/ – is the XML Schema language. This contains the basic data types.
- http://www.w3.org/2001/XMLSchema – Used in xsi:type attributes to specify the data type.
- http://schemas.xmlsoap.org/soap/encoding/ – SOAP specific type encodings.
- https://phpbuilder.com/columns/adam_delves/email_validator.verify/
– this URI does not exist but serves to identify the name space for the
verify method of the email validator
its own, an RPC called using SOAP looks like a bloated XML-RPC call.
Using XML, RPC would be a lot less expensive, parsing wise, than using
SOAP. Web Services Description Language (WSDL) serves to put SOAP-RPC
into context. A WSDL file which compliments a web service describes all
the operations and data types that the web service interface exposes. This
is especially useful in object-orientated programming languages as it
enables the client using the web service to automatically replicate any
required objects, methods and data types and decode the SOAP responses
appropriately.
language. The client initialises their web service with the URI or path
of the WSDL file (which need not reside on the same server as the
service endpoint) and generates proxy code on the fly.
SOAP is not enabled by default in PHP, you may need to enable it before
continuing. There are two main SOAP implementations available, PEAR-SOAP and PHP’s own SOAP extension.
Where it is available PHP’s own extension should be used, as it is written in C,
and is faster and more efficient than the PEAR implementation. In this
article, the code samples will apply to PHP’s SOAP extension.
SOAP extension is not enabled by default in PHP. It is however included
as part of the source code and as a dll file in the Windows ZIP
distribution. To check whether the SOAP extension is already enabled,
create a file containing a call to phpinfo() and check for a section named SOAP.
enable the SOAP extension on a Windows system you must add the
following line to your php.ini configuration file in the extensions
section and ensure that the file php_soap.dll is contained in the
directory specified in the extension_dir setting:
extension=php_soap.dll
enable SOAP support on a UNIX system, you must re-compile the PHP
interpreter. The SOAP extension also requires a libxml-2.5.4 or
greater, which can be obtained from XMLSoft, assuming none are present on your system. First download and install libxml, then recompile PHP.
# wget ftp://xmlsoft.org/libxml2/libxml2-2.6.11.tar.gz
# tar xzvf libxml2-2.6.11.tar.gz
# cd libxml2-2.6.11
# ./configure
# make
# su -c "make install"
# wget http://uk2.php.net/get/php-5.1.4.tar.gz/from/uk.php.net/mirror
# tar zxvf php-5.1.4.tar.gz
# cd php-5.1.4
# ./configure --enable-soap
# make
# su -c "make install"
of the WSDL file containing all the information on how to interact with
the web service. At this point, the object is initalised with all the
methods of the web service and can be called as functions of the soap
client.
PHP:
$params->AWSAccessKeyId = AMAZON_API_KEY;
$params->Request->SearchIndex = 'Books';
$params->Request->Keywords = 'php5 oop';
$amazon = new SoapClient('http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl');
$result = $amazon->itemSearch($params);
- The
Amazon web service API’s require the parameters to be sent in the form
of an object. This is initialized with all the appropriate values first. - First an instance of the SoapClient object is created using the URI of the WSDL file.
- The
itemSearch() operation which is now a method of the SoapClient object
is called. This causes PHP to make an HTTP request to the web service,
sending a SOAP envelope containing the RPC call. - The return
value of the itemSearch operation sent back from the web service is
returned by the itemSearch() method and is decoded into native PHP
types automatically. - The result, like the parameter passed to
the function, is in the form of an object. If the request is successful,
the Item property will contain an array of Item objects for the items
found.
function of the SoapClient object returns useful information about the
data types supported by the web service. Being an untyped language,
most of this information is irrelevant to us. However, the object data
types can still be replicated in PHP and mapped to the data types
exposed by the web service.
proxy generator class creates and returns an instance of the
SoapClient. However, prior to this it uses the __getTypes() function to
create all the class objects and maps them in the classmap array passed
in the SoapClient’s constructor.
PHP wsdl_proxy_generator.php:
class WSDLProxyGenerator
{
/**
* Creates an instance of a SoapClient object and all necessary suporting types.
*
*/
public static function createSoapClient($wsdlUri, $clientName='WsdlGerneratedWebService')
{
/* create the SoapClient object using the wsdl file */
$soap = new SoapClient($wsdlUri);
$types = array();
foreach($soap->__getTypes() as $type) {
/* match the type information using a regualr expession */
preg_match("/([a-z0-9_]+)s+([a-z0-9_]+([])?)(.*)?/si", $type, $matches);
$type = $matches[1];
switch($type) {
/* if the data type is struct, we create a class with this name */
case 'struct':
/* the PHP class name will be ClientName_WebServiceName */
$className = $clientName . '_' . $name;
/* store the data type information in an array for later use in the classmap */
$types[$name] = $className;
/* check the class does not exsits before creating it */
if (! class_exists($className)) {
eval("class $className {}");
}
break;
}
}
/* create another instance of the SoapClient, this time using the classmap */
return new SoapClient($wsdlUri, array('classmap' => $types));
}
/* this class cannot be instantiated as an object */
private function __construct()
{
}
}