You are on page 1of 13

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

Access an enterprise application from a PHP script


Using the PHP 5 SOAP extension to consume a WebSphere Web service

Level: Intermediate Caroline Maynard (caroline.maynard@uk.ibm.com), Software Engineer, IBM UK Laboratories Graham Charters (charters@uk.ibm.com), Software Engineer, IBM UK Laboratories Matthew Peters (matthew_peters@uk.ibm.com), Software Engineer, IBM UK Laboratories 25 Feb 2005 Many Web developers enjoy the versatility and ease of use of PHP, but sometimes they need to access existing business logic in a J2EE application server. In this article and through code examples, learn how to use the new SOAP extension in PHP 5 to access a J2EE application using Web services, without having to leave the PHP environment or learn a new programming model.

Introduction to PHP, Web services, and SOAP


This article shows you how to access an enterprise application from a PHP script. You may be a PHP programmer who needs to write code for a departmental Web application to access a central corporate service, exposed as a Web service. Or you may be an experienced J2EE developer who wants to know a little more about PHP and how you can use it. The example in this article is an Enterprise JavaBean (EJB) running in an IBM WebSphere Application Server, but this article is not about how to deploy the Web service. Its focus is on how to consume the Web service from PHP, and it's applicable however the Web service is implemented.
What is PHP?

PHP: Hypertext Preprocessor (PHP) is a popular server-side scripting language for creating dynamic Web content. The PHP interpreter is available as source code or as pre-compiled binaries for major platforms, including most Linux distributions, Windows, Mac OS X, and iSeries. Literally millions of Web servers are running PHP, the vast majority of which are using PHP version 4. The latest release, PHP 5, became available in July 2004, and is seeing increasing adoption. PHP 5 introduces improvements to the object model; also, the underlying memory management has been redesigned with multi-threading and performance in mind. However, you need to watch out for a few backward-incompatible changes, which are documented in the PHP manual (see Resources).
What are Web service technologies?

The concept of Web services is to enable self-contained, modular applications, where the client and the service are loosely coupled. See Resources for pointers to detailed information about Web services. For this article, though, you'll need to know a little about the major technologies: SOAP (Simple Object Access Protocol), which specifies messages flowing between a client and server. The messages are formatted in XML. SOAP is independent of the platform, programming language, network, and transport layer.This article discusses using SOAP over HTTP. WSDL (Web Services Description Language), which is an XML-based language for describing a Web service, including its location, formats, operations, parameters, and data types. UDDI (Universal Description, Discovery and Integration), which provides a way to store and retrieve information about Web services in the network, using APIs and a UDDI Registry implementation. This article includes examples of SOAP messages and WSDL documents, but not UDDI.

1 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

A useful facility for Web services is the XMethods Web site (see Resources), where you can find a list of publicly available Web services implemented on a wide range of server platforms. You can easily adapt the examples in this article to access a service of your choice from XMethods.
SOAP and PHP

Several offerings let you use SOAP from PHP 4 scripts, the most popular being PEAR::SOAP and NuSOAP. At the time of writing, both of these had some compatibility issues with PHP 5, though updates were expected shortly. New in PHP 5 is a built-in SOAP extension, which we'll refer to as ext/soap. It is supplied as part of PHP, so you don't have to download, install, and manage a separate package. It is the first SOAP implementation for PHP to be written in C, rather than in PHP, and the authors claim that it is significantly faster as a consequence. Because the new extension is an integral part of PHP, the documentation is published in the Function Reference of the PHP Manual (see Resources). The SOAP reference starts with an important disclaimer: Warning: This extension is EXPERIMENTAL. The behavior of this extension -- including the names of its functions and anything else documented about this extension -- may change without notice in a future release of PHP. Use this extension at your own risk. This warning looks a bit alarming, but in practice, the extension seems to be well-supported. Like any new code, there are bugs to be found, but reported problems are usually fixed promptly. You can see the bugs list on the PHP site (see Resources). We expect the extension will be moved from experimental to mainstream in a future release of PHP.

Installing the PHP SOAP extension


You should have PHP 5 up and running in your Web server. We did our experimentation with PHP 5.0.2, which was the latest release at the time, and which has quite a few fixes for bugs in the initial release of PHP 5. As we've said, ext/soap is shipped as part of PHP 5, so you don't need to download anything extra, but you may have to make some changes to enable it. Which changes you need to make depend on whether you downloaded the source code and compiled PHP yourself, or downloaded binaries. If you downloaded the PHP source code and compiled it for your platform, you will probably need to rebuild, because ext/soap is not enabled by default. Repeat your previous build process, adding the --enable-soap option to the configure command. If you downloaded pre-compiled platform binaries, they may have ext/soap compiled in but not loaded, so you'll need to update your PHP configuration to load ext/soap. Edit your php.ini, and look for the Dynamic Extensions section. Here you'll need to add a line that causes the extension to be loaded automatically. On Windows, this will be: extension=php_soap.dll On UNIX: extension=php_soap.so And if you haven't previously loaded any optional extensions, you may also have to set the extension_dir directive to point to the directory containing the extension libraries, including php_soap, for example: extension_dir="C:/php/ext/" (use forward slashes even on Windows) Don't try to put directory information in the extension directive; use extension_dir if

2 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

necessary. For Windows, you can download two alternative binary packages. The Windows installer package doesn't include any extensions, so use the Windows zip package instead, which does include ext/soap. Note that ext/soap depends on the GNOME xml library, which must be at version 2.5.4 or greater. If you don't already have the required level, install the libxml2 package from xmlsoft (see Resources). Finally, ext/soap has its own configuration section in php.ini. As shipped, this looks like:
[soap] ; Enables or disables WSDL caching feature. soap.wsdl_cache_enabled=1 ; Sets the directory name where SOAP extension will put cache files. soap.wsdl_cache_dir="/tmp" ; (time to live) Sets the number of second while cached file will be used ; instead of original one. soap.wsdl_cache_ttl=86400

This configuration section controls the WSDL caching feature of the SOAP extension. So by default, WSDL descriptors will be cached in your /tmp directory for 24 hours (86400 seconds). We'll look at this more later, but for now, set soap.wsdl_cache_enabled=0; otherwise, you may see some puzzling behavior as you develop your code. When your development is complete, remember to turn WSDL caching on, so your code will go faster. For reference, we used ext/soap in two environments: Linux Centos 3.3 (a free rebuild of Red Hat EL 3), Apache 2.0.47, PHP 5.0.2. We needed to upgrade libxml2 to 2.6.12 Windows XP SP1, Apache 2.0.46, PHP 5.0.2 binary zip package, libxml2 2.6.11 But these instructions are applicable in other configurations.

The Weather Forecast application


The Web service we're going to consume from PHP is a weather forecast application. It's the sample application developed in the WebSphere Version 5.1 Application Developer 5.1.1 Web Services Handbook. To download the sample Weather Forecast application, see the Download section later in this article. The book develops several different scenarios, but we'll work with just one, which the book calls "bottom-up development by generating a Web service from a session EJB, using HTTP as the transport for the SOAP messages". Here bottom-up means that the Web service is wrapped around an existing enterprise application. Figure 1. The Weather Forecast application

3 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

The main parts of the Weather Forecast application, as numbered in Figure 1, are: 1. The back-end WEATHER database of weather predictions. The information contained in a weather prediction is: Wind direction in an eight-point compass Wind speed in kilometers per hour Temperature in degrees Celsius Weather condition: sunny, partly cloudy, cloudy, rainy, stormy Date WeatherPredictor class is used to access the WEATHER database. If no prediction is available in the database for a requested date, the WeatherPredictor generates a random prediction (rather like real-life weather forecasts) and saves it in the database. 2. The business logic, which is provided by the WeatherForecastEJB session bean. Exposed as a Web service, it offers three operations: getDayForecast returns the weather forecast for one specific day getForecast returns the weather forecast for a period of time getTemperatures returns the temperature prediction for a period of time All the elements required to deploy the session bean as a Web service were generated by WebSphere Studio Application Developer's Web service wizard, as the ItsoWebService2RouterWeb project. The router servlet, which bridges between SOAP messages and the EJB container, is configured and deployed to make the Weather service available, with the URL ItsoWebService2EJBRouterWeb/services/WeatherServiceEJB. The WSDL document, itso.session.WeatherForecastEJB.wsdl, is made available in the ItsoWebService2EJBRouterWeb/wsdl directory. 3. The Java client, which is one of several clients for the Weather Service developed in the book. The WeatherClientEJB, from the ItsoWebService2EJBClient project, is a simple Java servlet that invokes the getForecast Web service operation. A typical run looks like this: Figure 2. The Java WeatherClient

The next step is to build the equivalent client function in PHP. You don't need to run the sample yourself to read this article. You may prefer to build a PHP client for a Web service you've chosen from the XMethods Web site (see Resources). But if you do want to install the Weather Forecast sample, the book provides comprehensive instructions in Appendix B. You'll need to: Set up the WEATHER database (page 528) Set up the WebSphere test server (page 529 - 533); you don't need to configure a JMS server Import the sample project into Application Developer (page 539 - 540); only the ItsoWebService2xx workspace projects are needed

4 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

A PHP Weather client


In this section you'll see how we built up our PHP Weather client. We include code snippets here, but we suggest you download the completed client and the WSDL file (see the Download section). The ext/soap class we'll use to represent the Weather Service is the SoapClient. As we discussed when describing the Weather Forecast application, we know that our application server is serving up the WSDL at http://host:port/ItsoWebServer2RouterWeb/wsdl/itso/session/WeatherForecastEJB.wsdl. We're using the default port and working on the same computer as the server, so we can create our first SoapClient by looking up the WSDL file:
<?php $soapClient = new SoapClient("http://localhost:9080/" . "ItsoWebService2RouterWeb/wsdl/itso/session/WeatherForecastEJB.wsdl"); ?>

Note that, because ext/soap is built-in, we didn't need any include or require statement before referring to SoapClient. Now we've instantiated our client, we want to contact the Weather service and invoke its getForecast operation. A nice feature of ext/soap is that when we use the SoapClient in WSDL mode, we can refer to the remote operation directly, as if it were a function of SoapClient itself. But when it comes to building the input parameters, things get a bit fiddlier. ext/soap can provide an array of the operations and parameters it has determined from the WSDL:
$functions = $soapClient->__getFunctions(); print_r($functions); $types = $soapClient->__getTypes(); print_r($types);

Showing just the results relevant to the getForecastoperation, and reformatting them for readability, we see:
getForecastResponse getForecast(getForecast $parameters) struct getForecast { dateTime startDate; int days; } struct getForecastResponse { Weather getForecastReturn; } struct Weather { string condition; dateTime date; string windDirection; int windSpeed; int temperatureCelsius; boolean dbflag; }

ext/soap doesn't actually define a getForecast class for us to construct; we have to create an array of the required input parameters to the operation:
$getForecastParam = array('startDate' =>time(), 'days' => 3);

and then invoke the operation as a method of SoapClient:


$forecastResponse = $soapClient->getForecast($getForecastParam);

Finally we'll take the returned getForecastResponse object, which is itself an array of Weather

5 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

objects, and display the results in a table:


echo "<table border=1 cellpadding=5>"; echo "<tr><th>Date</th><th>Condition</th><th>Temperature</th><th>Wind</th></tr>"; $weatherArray = $forecastResponse->getForecastReturn; foreach ($weatherArray as $weather) { echo "<tr>", "<td>",strftime("%a. %b %d, %Y", strtotime($weather->date)),"</td>", "<td>$weather->condition</td>", "<td>$weather->temperatureCelsius</td>", "<td>$weather->windDirection $weather->windSpeed</td>", "</tr>"; } echo "</table>";

The output of the PHP client is identical to the Java client, and we learn that there won't be snow in San Jose this Christmas time... Figure 3. The PHP WeatherClient

Watching the SOAP flows


We've managed to contact the Weather service and display the results. But what if something goes wrong, and we don't get the response we expected? ext/soap can display the SOAP messages flowing between client and server, which may help us to identify a problem. The trace functions only work when the SoapClient is created with the trace option. We set the trace option in an options array parameter, which we pass to the SoapClient constructor. We modify our use of the constructor to:
$soapClient = new SoapClient("http://localhost:9080/" . "ItsoWebService2RouterWeb/wsdl/itso/session/WeatherForecastEJB.wsdl", array('trace' => 1));

And call the trace methods after invoking getForecast:


echo "Request :<br>", htmlspecialchars($soapClient->__getLastRequest()), "<br>"; echo "Response :<br>", htmlspecialchars($soapClient->__getLastResponse()), "<br>";

It's essential to use the htmlspecialchars built-in function to encode the trace output, because it translates the SOAP xml delimiters to special characters, for example <. This prevents the browser from interpreting them as markup. Here's an example of the trace output for a request :

6 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://session.itso"> <SOAP-ENV:Body> <ns1:getForecast> <ns1:startDate>2004-11-30T13:41:59</ns1:startDate> <ns1:days>0</ns1:days> </ns1:getForecast> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

And the corresponding response:


<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <getForecastResponse xmlns="http://session.itso"> <getForecastReturn xmlns:ns-239399687="http://mapping.itso"> <ns-239399687:condition>sunny</ns-239399687:condition> <ns-239399687:date>2004-11-30T00:00:00.000Z</ns-239399687:date> <ns-239399687:windDirection>W</ns-239399687:windDirection> <ns-239399687:windSpeed>18</ns-239399687:windSpeed> <ns-239399687:temperatureCelsius>6</ns-239399687:temperatureCelsius> <ns-239399687:dbflag>1</ns-239399687:dbflag> </getForecastReturn> </getForecastResponse> </soapenv:Body> </soapenv:Envelope>

When we ran our client with tracing on to collect this output, we set the days parameter to 0, just so that the SOAP response would take fewer lines to print. But in doing so, we came across some unexpected behavior. We had expected the getForecastResponse to be an array of Weather objects as before, but to have just one element instead of four. Instead, it turned out to be a simple Weather object, and we had to code around this behavior, as you can see in the finished code for the sample PHP client. This was different from the behavior in the Java client, where getForecast always returned an array of Weather objects, regardless of how many were carried in the server response. The output of SoapClient::_getTypes() doesn't give enough detail for us to understand this discrepancy, so we'll take a look at the WSDL document for a full specification of the interface.

Interpreting the WSDL


We've managed to invoke the Weather service without ever looking at its WSDL document. But there's a lot more detail in the WSDL than the SoapClient exposes. How did we know what to put in the startDate parameter? What should we really expect in the returned data? To answer these questions, we need to look in more detail at the WSDL. You can download the WSDL for the Weather Forecast application from the Download section. If you're working with a different Web service, just open up the WSDL document in your browser. The WSDL for the getForecast operation is:
<wsdl:operation name="getForecast"> <wsdl:input message="intf:getForecastRequest" name="getForecastRequest"/> <wsdl:output message="intf:getForecastResponse" name="getForecastResponse"/> </wsdl:operation>

Where the getForecastRequest message is defined as:


<wsdl:message name="getForecastRequest"> <wsdl:part element="intf:getForecast" name="parameters"/> </wsdl:message>

7 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

And the getForecast structure is defined as:


<element name="getForecast"> <complexType> <sequence> <element name="startDate" nillable="true" type="xsd:dateTime"/> <element name="days" type="xsd:int"/> </sequence> </complexType> </element>

So we know that the function requires two parameters, startDate of type xsd:dateTime, and days, an integer. This matches what we learned from the SoapClient::_getTypes function, but now we also know that startDate is nillable. Sure enough, if we simplify our input parameters, thus:
$forecastResponse = $soapClient->getForecast(array('startDate'=>Null, 'days'=>3));

The result is the same as if we had specified today's date explicitly. What if we wanted to specify some other start date? The XML Schema (see Resources) defines dateTime as a primitive type, which should be formatted according to the ISO 8601 standard, for example "2004-12-01T00:00:00". Suppose we want the weather forecast starting three days from now. We can get from PHP the required date, using the built-in function strtotime("+3 days"), which, like the time() function, returns the date and time in the standard UNIX format of an integer representing seconds since the Epoch. Because we knew that the XML Schema required the date to be encoded in a stringified ISO 8601 format, we wrote the timeToIso8601 function in our sample client to convert the integer date to the format defined for the SOAP encoding. But we were surprised to discover this was not necessary; ext/soap is smart enough to convert the integer date to the required stringified format for us. It doesn't matter whether we pass in an integer or a pre-formatted string, the SOAP messages that flow as a result are identical. What about the date in the response? On the return trip, ext/soap gets the dateTime field from the SOAP response, but doesn't do any format conversion for us. We might like it to be returned as an integer representing seconds since the Epoch, but in fact we are given a string formatted according to ISO 8601. So we use the strtotime function to convert this to an integer, and then strftime to format it for presentation. The Weather Service provides forecasts by date, and ignores the time element of the dateTime encoding. Therefore, we didn't concern ourselves with any adjustments that might be necessary for requesting a forecast from a service running in a different time zone. If you would like more details about converting between time zones, see Resources for an article describing the ISO 8601 standard. Now let's return to the format for the response. In the previous section, we noticed an inconsistency in the data returned from getForecast. The WSDL description tells us that getForecast returns a getForecastResponse object, and that a getForecastResponse contains an unbounded sequence of instances of a complex type called Weather:
<element name="getForecastResponse"> <complexType> <sequence> <element maxOccurs="unbounded" name="getForecastReturn" type="tns2:Weather"/> </sequence> </complexType> </element> <complexType name="Weather"> <sequence> <element name="condition" nillable="true" type="xsd:string"/> <element name="date" nillable="true" type="xsd:dateTime"/> <element name="windDirection" nillable="true" type="xsd:string"/> <element name="windSpeed" type="xsd:int"/> <element name="temperatureCelsius" type="xsd:int"/> <element name="dbflag" type="xsd:boolean"/> </sequence> </complexType>

8 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

The WSDL doesn't allow for any special case for a single-element array. It's unfortunate that ext/soap doesn't honor the <sequence> tag in the WSDL for the getForecastResponse when the response has only one Weather object, because this behavior causes unnecessary complexity in the client code. Lastly, the WSDL document also tells the SOAP client where in the network it can find the service:
<wsdl:service name="WeatherForecastEJBService"> <wsdl:port binding="intf:WeatherForecastEJBSoapBinding" name="WeatherForecastEJB"> <wsdlsoap:address location= "http://localhost:9080/ItsoWebService2RouterWeb/services/WeatherForecastEJB"/> </wsdl:port> </wsdl:service>

Handling SOAP Faults


What happens if an error occurs when we run our client? New in PHP 5 is an exception mechanism, similar to that found in other languages, such as Java. ext/soap uses this new mechanism to return errors in the form of a SoapFault object. For example, we can surround our code with:
try { ... some SOAP operation } catch (SoapFault $soapFault) { echo $soapFault; }

Note that, unlike Java, a PHP try - catch block can not have a finally clause. A SoapFault may be locally generated. Suppose, for example, that we mistype the name of the startDate parameter to getForecast. The output of our client is:
SoapFault exception: [SOAP-ENV:Client] SOAP-ERROR: Encoding: object hasn't 'startDate' property in WeatherClientEJB.php:32 Stack trace: #0 WeatherClientEJB.php(32): SoapClient->getForecast('getForecast', Array) #1 WeatherClientEJB.php(73): displayForecast(Array) #2 {main}

Note there was no trace output, because no request was sent. SOAP_ENV:Client is one of the values defined in the SOAP specification for the Faultcode field of the Fault body element. That SoapFault was generated from within ext/soap when it detected the error, and no SOAP message was sent. But SoapFaults can also report errors detected at the server. For example, suppose we modify our code so that the value of the startDate parameter is "badDateString".This is not a valid ISO 8601 string, but ext/soap doesn't validate the format we provided; it just sends the message to the server, which rejects the request:
Request : <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://session.itso"> <SOAP-ENV:Body> <ns1:getForecast> <ns1:startDate>badDateString</ns1:startDate> <ns1:days>2</ns1:days> </ns1:getForecast> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Response : <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body>

9 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

<Fault xmlns="http://schemas.xmlsoap.org/soap/envelope/"> <faultcode xmlns="">Server.generalException</faultcode> <faultstring xmlns=""> <![CDATA[java.lang.NumberFormatException: WSWS3046E: Error: Invalid date/time: badDateString]]> </faultstring> <detail xmlns=""/> </Fault> </soapenv:Body> </soapenv:Envelope> SoapFault exception: [Server.generalException] java.lang.NumberFormatException: WSWS3046E: Error: Invalid date/time: badDateString in WeatherClientEJB.php:32 Stack trace: #0 WeatherClientEJB.php(32): SoapClient->getForecast('getForecast', Array) #1 WeatherClientEJB.php(73): displayForecast(Array) #2 {main}

This time, the SOAP request was delivered to the server, but was rejected because of the invalid date format. The WeatherForecastEJB implementation threw a java.lang.NumberFormatException, which was returned in the SOAP response as a Fault body element, and reported to the client as a SoapFault exception.

Securing the Web service


We'll look at three approaches to security, and how we can use them from PHP: Basic HTTP authentication When an HTTP server requires a client to authenticate, it requests a userid and password by adding an Authentication Required HTTP header to a response. The client must respond with a request containing an acceptable Authorization HTTP header before it can proceed. Normally it will be the Web server that requests HTTP authentication, not the Web service provider. The Authentication Required HTTP header flows to the browser, which pops up a dialog box requesting a userid and password, and then sends the user's response to the Web server as an HTTP Authorization header. It's easy to do this from a PHP script, using the header() function to send the required HTTP header fields. For example:
if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="Weather"'); header("HTTP/1.0 401 Unauthorized"); } echo "Welcome " . $_SERVER['PHP_AUTH_USER'];

The section HTTP authentication with PHP of the PHP manual describes the process in detail. You may come across some Web services where the web service provider requires the PHP web service client authenticate using HTTP. ext/soap gives us a simple way to send the HTTP Authorization request header, using the options array passed to the SoapClient constructor:
$soapClient = new SoapClient("http://localhost:9080/" . "ItsoWebService2RouterWeb/wsdl/itso/session/WeatherForecastEJB.wsdl", array('login' => "userid", 'password' => "password"));

However, HTTP Basic authentication is not considered to be a secure method of user authentication, (unless used in conjunction with some external secure system such as SSL), because the user name and password are passed over the network as clear text. HTTP Digest authentication improves this by encrypting the password, but not all browsers support it. Also, PHP's header() function supports only basic authentication. SSL (Secure Sockets Layer) A more secure protocol is HTTPS (HTTP over SSL), which uses SSL to encrypt HTTP messages.

10 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

SSL works at the transport level, and does not understand the HTTP or SOAP protocols. For that reason, it cannot encrypt just the sensitive elements of a message; it must encrypt the entire message. HTTPS can be used between the browser and the Web server, and/or between the Web server and the Web service provider. PHP supports HTTPS if OpenSSL has been compiled in and enabled. See the OpenSSL section of the PHP manual for how to use SSL in your PHP script. What about authentication? SSL can send a security certificate, which the other party can accept or reject. This works nicely if the requirement is for the client to authenticate the Web service provider, for example, for an e-commerce application. But if the Web service itself is providing access to sensitive information, then the Web service provider needs to authenticate each client, too. Certificate-based authentication isn't appropriate, because the clients are likely to be numerous and dynamic; it would not be feasible to distribute a suitable certificate to every client in advance. WS-Security The WS-Security standard provides a different approach to Web service security. So far we've looked at security controls that are outside the SOAP protocols. But WS-Security works by adding security headers to the SOAP messages. For example, for WS-Security basic authentication (not the same as HTTP basic authentication!), the tags
<wsse:UsernameToken> <wsse:Username>userid</wsse:Username> <wsse:Password>password</wsse:Password> </wsse:UsernameToken>

would flow in the SOAP headers. That was a simple example, but the full set of security extensions is comprehensive, including not only authentication, but also integrity, confidentiality, and so on. Currently, there's no first-class support in ext/soap for WS-Security. Therefore, if we're going to send and receive WS-Security headers in PHP, we'll have to drop down into a more detailed interface where we can explicitly create the SOAP headers. So far, our example has shown the use of ext/soap's WSDL mode. But there is also a non-WSDL mode, in which you have control over the details of the SOAP messages. Of course, you have to do a lot more work in your code, too. You build up the message elements using the SoapHeader, SoapParam, and SoapVar classes, and then use SoapClient::__call to send the SOAP request and get the response. It would be quite a laborious task to code the Web services security extensions (or any of the other advanced specifications, such as WS-Transactions) in PHP in the absence of any built-in support, and we don't attempt it in this article.

Summary
It's simple to get started with the PHP SOAP extension. You can develop a PHP script to consume a simple Web service in just a few lines of code, regardless of how the server is implemented. As usual, PHP excels with its ease of use. Our focus in this article has been on using the SoapClient class to access an existing Web service in a heterogeneous network, but you can also deploy a Web service with ext/soap, using the SoapServer class, which is similarly intuitive. When we try to handle more complex interactions, ext/soap in its current version doesn't give us much help. The mappings from the XML schema to PHP are sometimes unclear, and can only be verified by experiment, or studying the source code. And if we want to use more advanced Web services protocols, our only option is to drop down into non-WSDL mode and create the SOAP headers in our own script, which is tedious and error prone. One of the key claims for Web services is interoperability between platforms, operating systems, and

11 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

programming languages. The independent WS-I (Web Services Interoperability) Organization provides a test suite to verify conformance to its Basic Profile, and we'd like to see ext/soap reach a level where it could demonstrate compliance. We hope that ext/soap will continue to develop, and become a mainstream extension of PHP.

Downloads
Description Sample Weather Forecast application Sample PHP Weather client WSDL document for the Weather service WebSphere Version 5.1 Web Services Handbook Name sg246891-01code.zip WeatherClientEJB.zip WeatherForecastEJB.wsdl sg246891.pdf Size Download method

2690 KB FTP 2 KB HTTP 7 KB HTTP 5.9 MB HTTP

Information about download methods

Get Adobe Reader

Resources
The WebSphere Version 5.1 Application Developer 5.1.1 Web Services Handbook (IBM International Technical Support Organization, February 2004) explains how to develop and use Web services using WebSphere Studio Application Developer. From this page you can download the sample application, view the book online, download it as a PDF, and order hardcopy or CD-ROM. Also see the Download section for the sample code. At the PHP language home page, PHP.net, you'll find the ext/soap manual and the bugs list (set the Category to "SOAP related"). Download the prerequisite GNOME xml library from xmlsoft.org. The XMethods site lists publicly available Web services. Read the description of the PHP SOAP extension, by Dmitry Stogov, one of it authors. The W3C XML Schema is defined by the specifications at w3.org. Markus Kuhn's Summary of the International Standard Date and Time Notation explains the ISO 8601 standard. Visit the Web Services Interoperability Organisation. The developerWorks SOA and Web services zone contains a wealth of material, with an overview page at New to Web services. Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products. Innovate your next open source development project with IBM trial software, available for download or on DVD. Browse for books on these and other technical topics. Get involved in the developerWorks community by participating in developerWorks blogs.

12 of 13

1.7.2008 12:05

Access an enterprise application from a PHP script

http://www.ibm.com/developerworks/opensource/library/os-phpw...

About the authors


Caroline Maynard works at IBM's development lab in Hursley, England, where she has worked in diverse areas including networking, graphics, and voice. Most recently she led the development of the IBM Java ORB, which underpins the WebSphere Application Server's EJB container. She is interested in the integration of IBM offerings with open-source LAMP (Linux, Apache, MySQL, and PHP/Perl/Python) technologies. Caroline holds a degree in Mathematics from the University of Sussex.

Graham Charters works at IBM's development lab in Hursley, England. Past roles have included WebSphere Application Server development, along with architecture responsibilities in WebSphere Business Integration, and Adapters. His current interests are in the relationships between open source technologies, such as those of LAMP (Linux, Apache, MySQL, PHP/Perl/Python) and the IBM WebSphere platform. Graham holds degrees in Computer Science, Numerical Analysis, and Machine Vision, all from the University of Manchester.

Matthew Peters works at IBM's development lab in Hursley, England. He has worked in various roles on IBM's CICS and MQSeries products and spent a number of years working with partners in scientific and technical computing and large-scale parallel processing. In recent years he worked on the garbage collector in the IBM JVM. Matthew has a degree in Mathematics from Queens' College, Cambridge, and an MSc in Software Engineering from Oxford University.

13 of 13

1.7.2008 12:05

You might also like