Tech Ads
Back to Article List
Originally published January 2004 [ Publisher Link ]
PHP Web Services with PEAR
PHP -- short for PHP Hypertext Preprocessor -- was, along with Perl, one of the frontrunners in server-side programming long before any JSP/Servlet or ASP technology came to be. It is often the language of choice for those using Apache's Web server, which runs almost 70% of sites on the Web. Due to its pervasiveness, it seems obvious that it should support the most recent standards, such as SOAP, which are also adopted by major technology vendors. In this article, we will describe how Web services can be implemented in PHP.
In a previous article, we explored how to design and deploy Web services based on Java using the Axis SOAP engine and Tomcat J2EE-Servlet/JSP container. Although not a prerequisite for the following article, reading it will give you a firmer grasp on the whole Web services picture, since you will be able to use the PHP Web service described here to communicate with another service written in Java, and vice versa, allowing you to experiment firsthand with Web services interoperability.
PHP Web services suites
PHP has various ways in which you can implement Web services, including NuSOAP, PHP-SOAP, and PEAR (PHP Extension and Application Repository). Some of these packages are more mature than others, but in essence they achieve the same goal, which is to deploy Web services in PHP. We will use PEAR, which is is not a standalone package for Web services but more of a framework for building PHP applications, and which includes a Web services module.
PEAR download and installation
To begin, you need an Apache Server -- either the 1.x branch or the 2.x version enabled with PHP. Depending upon the PHP version you have installed, you may still need to download the PEAR Package Manager, which is in charge of administering all of PEAR's modules and functionality.
You can query your PHP version by executing the command php --version
from a shell prompt. If the version is lower than 4.3, you need to invoke the following command from lynx, the console-based Web browser: lynx -source http://go-pear.org/ | php
. You will be prompted with various download questions; select the default options. You must use lynx because the interactive prompts do not allow you to use a GUI browser.
Once you have installed the PEAR Package Manager you can proceed to installing the necessary PEAR modules for using SOAP in PHP, this is done with the pear install [Module_Name]
command. If you execute this command while you have an active connection to the Internet, it will automatically download and install the module in your local environment. In case you don't have an active connection, you will need to download the SOAP package for PEAR as well as some prerequisite PEAR modules from http://pear.php.net/packages.php in order to install the SOAP package, including Mail_Mime
, Net_URL
,
HTTP_Request
, and Net_DIME
.
Now that you have installed the SOAP PEAR module, we are ready to start designing our Web service.
The Web service
The following service is quite similar to the one described in my earlier Java Web services article. It is designed to return a particular result based on two integers provided by a Web services client. For simplicity, all data is coded directly in the PHP script; a more comprehensive Web service would normally include a database connection for extracting information in real time, but since this is not our primary intention, the information is static in nature.
<?php require_once('SOAP/Server.php'); require_once('SOAP/Disco.php'); class Sales { var $__dispatch_map = array(); function Sales() { // Define the signature of the dispatch map on // the Web services method // Necesary for WSDL creation $this->__dispatch_map['onsale'] = array('in' => array('low' => 'integer', 'high' => 'integer'), 'out' => array('sales' => 'string'), ); } function onsale($low, $high) { if ($low < 1) { return "We have some bargains, but not at those prices!"; } else if ( $high < 100 ) { return "We have a few gadgets which fit your price range,visit our site for more details and pictures!"; } else { return "Thats more than spare change, have you considered donating some of it to an Open-Source project ? "; } } } $server = new SOAP_Server(); $webservice = new Sales(); $server->addObjectMap($webservice, 'http://schemas.xmlsoap.org/soap/envelope/'); if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD']=='POST') { $server->service($HTTP_RAW_POST_DATA); } else { // Create the DISCO server $disco = new SOAP_DISCO_Server($server,'Sales'); header("Content-type: text/xml"); if (isset($_SERVER['QUERY_STRING']) && strcasecmp($_SERVER['QUERY_STRING'],'wsdl') == 0) { echo $disco->getWSDL(); } else { echo $disco->getDISCO(); } } exit; ?> |
First off we declare the use of two PHP libraries. SOAP/Server.php is used in the creation of PHP Web services, and SOAP/Disco.php contains a series of methods employed in the generation of a Web Services Description Language (WSDL) file, necessary for creating the corresponding Web services client.
After declaring our main Web services class named Sales
, we
define an array field named $__dispatch_map
and a
corresponding constuctor class. These two declarations form an integral
part in the generation of the WSDL file for our Web service. Through the
constructor we are guaranteed that when the class is instantiated the
__dispatch_map
will be populated with a specific set of data.
Notice that this information corresponds to the input and output fields of
the onsale
method.The onsale
method contains the
core functionality of our Web service, as it returns an output based on the
parameters it is passed on invocation.
Once our main Sales
class is defined, we create an instance
for it, as well as for the SOAP_Server
class. We then call the addObjectMap
method, which is included in
SOAP_Server
, to associate our Sales
instance named
$webservice
with http://schemas.xmlsoap.org/soap/envelope/
, which is the standard namespace for sending SOAP message through the wire.
Next, we initiate a conditional to check what type of request is
being made on the PHP page. If we detect an explicit request method then
the service
method is invoked on the $server
instance defined previously, which returns a Web service result. If
the previous conditional does not hold true, then a
SOAP_DISCO_Server
instance is created on the Web service, which
facilitates returning a WSDL file for the requester. At this juncture, we
create one more conditional to inspect the URL and see if it contains a
wsdl
extension. If it does, then the corresponding
WSDL is returned; if not, then an absolute URL is returned indicating where
to extract the WSDL contract.
All set? Place the Web service PHP script, which from here on we will refered to as Sales.php, on your server.
WSDL for the Web service
WSDL is the standard language in which you describe Web services. It is an XML-based language that allows you to map a particular service in a language-agnostic manner.
In PEAR's case, you can obtain a WSDL contract for your
Web service through its SOAP_DISCO_Server
, described in the
earlier code. Unfortunately you do have to write some plumbing code to
facilitate this mechanism, unlike with Java's Axis procedure, in which simply appending the ?wsdl
snippet to the URL is enough to generate the WSDL contract.
The Web service we have designed in PHP allows you to use this same
mechanism of appending the ?wsdl
to the request in order to obtain the WSDL. However, you do need to code a constructor method for this task, as well as write some scaffolding to achieve it, all of this directly
coded in your Web service. This can be a considerable burden, espcially for
more complex Web services, but it is the only
way to achieve this behavior of obtaining a WSDL contract directly in PEAR's current SOAP version.
The Web service client
When creating a Web services client you normally feed the WSDL contract for the Web service you wish to contact into a specific language tool, which eases the writing of your code. Since our Web service is so simple we will be directly inspecting the contract and coding the client without any specific tools.
The following PHP-based Web service client is designed to be invoked from the command line:
#!/usr/local/bin/php <?php require('SOAP/Client.php'); if ($argc != 3 ) { printf("Usage : Customer lowestprice highestprice"); echo "\n"; } else { $endpoint = 'http://localhost/Sales.php'; # We could also use the URL's for the Java Web services # deployed via Axis/Tomcat #$endpoint = 'http://localhost:8080/axis/Sales.jws'; #$endpoint = 'http://localhost:8080/axis/services/Sales'; $customer = new SOAP_Client($endpoint); $method = 'onsale'; $int1 = (integer) $argv[1]; $int2 = (integer) $argv[2]; $params = array('lowprice' => $int1, 'highprice' => $int2); $ans = $customer->call($method, $params); printf($ans); echo "\n"; } ?> |
The Web service client first imports the SOAP/Client.php
library used in coding PEAR's Web services clients. Afterwords, we check
the parameters provided by the user at the command line to assure an
appropriate invocation.
Once the input is revised [ do you mean received? No, I mean checking the input for validity,e.g if the user inputs 2 integers ], we declare a string that holds the location of the Web service variable, which is later used to instaniate the SOAP_Client
class used in invoking a Web service. We then define the method which is to be called on the service, as well as an array containing the integers provided at run-time by the user.
Finally, we invoke the call
method on the
SOAP_Client
instance Customer
to directly call the Web service. This last method takes both the function that is to be called on the Web service and the input parameters. The results of this call are then printed out to the console.
The WSDL-Querying Web service client
The last example showed you the basics of invoking a Web service from a PHP environment. There is one more way you can create a Web service client from PEAR -- by directly querying the WSDL of a Web service. With this technique the Web service characteristics are taken and parsed directly from the WSDL file. As automatic as this may seem compared to the previous method, you still have to figure out somehow what parameters to pass to the Web service, which obviously requires a manual or tool-based inspection, so though it is different, it is not entirely automatic. Take a look for yourself:
#!/usr/local/bin/php <?php require_once 'SOAP/Client.php'; if ($argc != 3 ) { printf("Usage : Customer lowestprice highestprice"); echo "\n"; } else { $wsdl = new SOAP_WSDL ('http://localhost/Sales.php?wsdl'); # We could also use the URL's for the Java Web services WSDL # deployed via Axis/Tomcat #$wsdl = # new SOAP_WSDL ('http://localhost:8080/axis/Sales.jws?wsdl'); #$wsdl = new SOAP_WSDL( #'http://localhost:8080/axis/services/Sales?wsdl'); $Sales = $wsdl->getProxy(); $int1 = (integer) $argv[1]; $int2 = (integer) $argv[2]; echo ( $Sales->onsale($int1,$int2) ); echo "\n"; } ?> |
This Web service client is a command line program that begins by importing the SOAP/Client.php library, then further checks to see if the required parameters were indicated upon execution. Once the input validation is done, we create a SOAP_WSDL
instance which takes the URL where the WSDL contract resides. We later invoke the getProxy
method on this instance and assign it to the $Sales
variable. We place the two integers passed at run-time into the corresponding variables $int1
and $int2
, and finally, we print to console the results of calling the onsale
method on the $Sales
instance which takes these last integers as input.
Notice that even though we queried the WSDL directly, we knew beforehand
that an onsale
method existed and that it took two integers as
input. The actual Web service end-point is extracted from the WSDL as well
as other information, so it's not all that different from the first
Web services client we coded.
You have just deployed an end-to-end Web service using PHP --congratulations!