For consumption of a SOAP-based web service, PHP is practically self-documenting. The PHP language is all about growing by the community for the community. So, it is not unusual to find functions in the PHP language that started life as a custom class and grew into the base of PHP. You see similar things with PHP functions around SOAP.

Example application: No limits

The sample application combines many concepts into a pair of PHP scripts. Typically, there is greater separation of roles, but REST and SOAP can exist in the same application. This coexistence again illustrates the incredible flexibility of PHP.

This application is different from the typical IBM i centric application because there is no local data that is used by the application. Web services are used to retrieve data from remote servers and update a database table that can exist as part of an enterprise resource planning (ERP) system. The primary purpose is to retrieve currency rates from a public-facing web service. This level of integration levels the playing field by introducing PHP to an existing application and making IBM i a real-world contender in the cross-platform activities of the 21st century.

REST or SOAP

Web services typically come in two major flavors: REST and SOAP. SOAP is a formal standard and the PHP functions that make it up are defined at http://www.PHP.net. REST is an application of a different standard that is called Remote Procedure Call (RPC). Regardless of the approach, web services do a great job of making the communication between two computer systems simple and straightforward. There are advantages to both approaches, but, briefly, RESTful services are typically simple, straightforward requests for simple data elements, and SOAP services usually are complex and can provide for greater precision on data types.

Consider a sample application. First, the sample application display asks the user to select two currency types and an initial value. When selected, the user can click Get Rate and the PHP script takes it from there.

User display window for the web service sample application

Here is the PHP code that was used to build the application display and call the
various web services based on the action that is taken.

<style>
table {
border: 4px solid black; font-size:1em;
font-family:Arial;background-color: paleturquoise
}
body {
font-size:1em;
font-family:Arial;
background-color: lightgray
}
td, th {
border: 1px solid black;
}
</style>
<?php
include 'currency1.php';
if(isset($_POST['calcRate']))
{
echo "<h2>Simple Currency Rate Calculator </h2>";
echo "<hr>";
$conversionRate = getCurrencyRate($_POST['fromRate'], $_POST['toRate']);
echo '<table><tr><th>Parm</th><th>Value</th></tr>';
echo "<tr><td>From Currency</td><td>{$_POST['fromRate']}</td></tr>";
echo "<tr><td>To Currency</td><td>{$_POST['toRate']}</td></tr>";
echo "<tr><td>Conversion Rate</td><td>$conversionRate</td></tr></table>";
$fromAmount = (float) $_POST['fromAmount']; $toAmount = (float) $_POST['toAmount'];
$conversion = $fromAmount * $conversionRate;
echo "<br /><br />$fromAmount {$_POST['fromRate']} is worth $conversion
{$_POST['toRate']}";
echo "<hr>";
}
if(isset($_POST['loadRates'])) {
loadRates();
}

$option = getCurrencyCode('option');
sort($option);
//var_dump($option);
?>
<h2>PHP Currency Rate Web Service</h2>
<form name="currencyForm" method="POST" action="currencyForm.php">
Enter From Rate :
<select name="fromRate">
<?php foreach ($option as $listItem) {
echo $listItem;
}?></select><br/><br/>
Enter From Amount :
<input name="fromAmount" type="text" value="<?php echo $_POST['fromAmount'];
?>"><br/><br/>
Enter To Rate :
<select name="toRate">
<?php foreach ($option as $listItem) {
echo $listItem;
}?></select><br/><br/>
<input name="calcRate" type="submit" value="Get Rate">
<br /><br />
<input name="loadRates" type="submit" value="Load Rate">

</form>

REST

RESTful web services are designed to run much like what IBM i developers call an API. RESTful services are direct requests for specific information with little complexity. In the PHP landscape, things are kept simple. The sample application is going to retrieve an XML package that contains a list of currency codes. The XML package is transformed into a PHP array to provide the options in a drop-down list. Green screen applications typically provide for high productivity by keeping the 5250 data stream lightweight. If a user wants to see a list of possible values for an input field, they press F4 and a window opens where they select the value. That is where the performance hit is incurred, as the window pulls the data from DB2 upon request. In the web world, we use drop-down lists, which give the user a similar experience. Drop-down lists are typically populated before the initial page is presented. This means that an application with 20 input fields can run 20+ SQL statements before letting the user see the display.

This application has a function that contains all the code that is necessary to dynamically pull the list of currency codes hot from a web service and return an array of either the raw values or the values that are embedded in an option clause, as shown. This configuration gives the caller the flexibility to retrieve the list as they see fit and improve efficiency because they do not need to format the data in the option list, which is arguably the most common request. Later, you look at how to use the data cache to save the retrieved data and thus improve the overall performance of the application.

REST web services call return data

The getCurrencyCode() call, which is shown in Example 5-6 on page 118 and highlighted in bold, makes a RESTful request to a web service by using file_get_contents(). The code for this REST web services call is shown

<pre><?php
// Service Functions...
function getCurrencyCode($style = 'array') {
$currencyCode = 'http://www.currency-iso.org/dam/downloads/table_a1.xml';
$currencyCodeXML = file_get_contents ( $currencyCode );
$simpleXML = simplexml_load_string ( $currencyCodeXML );
foreach ( $simpleXML->CcyTbl->CcyNtry as $codes ) {
$Ccy = htmlentities ( ( string ) $codes->Ccy );
if ($Ccy) {
$CtryNum = htmlentities ( ( string ) $codes->CtryNm );
if ($style == 'option') {
$optionString = ' <option value="' . $Ccy . '"';
if ($Ccy=='USD' && $CtryNum == "UNITED STATES") //default country...
$optionString .= 'selected';
$optionString .= ">$Ccy - $CtryNum</option>\n";
$option [] = $optionString;
} else
$option [] = array (
'Code' => $Ccy,
'Country' => $CtryNum
);
}
}
if ($option)
return $option;
else
return false;
}
function getCurrencyRate($fromRate, $toRate) {
//$serviceURL = 'http://www.webservicex.net/currencyconvertor.asmx';
$serviceWSDL = 'http://www.webservicex.net/currencyconvertor.asmx?WSDL';
$currencySoapClient = new SoapClient ( $serviceWSDL );
$parms = array (
"FromCurrency" => $fromRate,
"ToCurrency" => $toRate
);
$responseObj = $currencySoapClient->ConversionRate ( $parms );
$conversionRate = $responseObj->ConversionRateResult;
return $conversionRate;
}
function loadRates() {
$conn = db2_connect ( '*LOCAL', 'PHPUSER', 'phpuser1' );
if (! $conn) {
echo 'Error connecting to DB2--error code ' . db2_stmt_error () . ' - ' .
db2_stmt_errormsg ();
exit ();
}
$sql = 'select * from zenddata.rates';
$stmt = db2_exec ( $conn, $sql );
if (! $stmt) {
echo 'Error accessing data--error code ' . db2_stmt_error () . ' - ' .
db2_stmt_errormsg ();
exit ();
}
print '<table border=2><tr><th>From Currency</th><th>To
Currency</th><th>Rate</th></tr>';
while ( $row = db2_fetch_assoc ( $stmt ) ) {
$rate = getCurrencyRate ( $row ['FROMCURRENCY'], $row ['TOCURRENCY'] );
$today = date ( 'm/d/Y' );
var_dump ( $today );
$sql2 = "update zenddata.rates set CONVERSIONRATE = $rate, CONVERTDATE =
'$today'
where FROMCURRENCY = '{$row['FROMCURRENCY']}' and
TOCURRENCY = '{$row['TOCURRENCY']}'";
$stmt2 = db2_exec ( $conn, $sql2 );
echo
"<tr><td>{$row['FROMCURRENCY']}</td><td>{$row['TOCURRENCY']}</td><th>$rate</td></t
r>";
echo 'Table Rates Updated in DB2</table>';
}
}
?></pre>

This function can be thought of as a way to capture the content of stream files from the “root” file system of the IFS. A web page is nothing more than a file and the URL is simply the address where the file is. PHP can handle that and, as a result, pulls the content that is provisioned by the web page. This web page in particular happens to be producing not HTML but XML that contains the values of the country codes, which is exactly what we need for the second web service. A sample of the structure of the XML file is shown

XML that is returned by the getCurrencyCode web service

After the web service is requested, we put the resulting XML file into a Simple XML Object.

This makes accessing the complex structure of the XML schema easy, as you can see by the foreach() loop that reads through it. Each iteration of the foreach() produces a Simple XML object from the next member of the original master list, which, again, is part of the elegance of PHP. After the country code and country name are parsed, the values are stored in a PHP array in either raw data format or prepared as an option list.

This function needs to run only once to populate both drop-down lists. The values can also be cached by using the free data cache in Zend Server and thus improve response time even more.

SOAP

The user selects a “from” and a “to” currency from the drop-down lists that are populated by the function that is described in “REST” on page 120. The two values that are selected are passed to another function that calls a SOAP-based web service. The SOAP service takes the inputs and returns the requested conversion rate. For example, a request of the conversion rate from USD (United States Dollars) to GBP (Great British Pound) yields a value of .5973. This value is used to calculate the converted dollar amount for display purposes.

One characteristic of a SOAP-based web service is that it is self-defining because of Web Services Description Language (WDSL). WSDL is typically provisioned and accessed before the web service is called. The level of detail of a WSDL file can be extensive, but this example is simple.

Unlike the RESTful web service, the SOAP service typically has two URLs: one for the WSDL and the other for the service call itself. In this case, there is a built-in class of PHP called SoapClient that can read the WSDL and start communicating with the service. In this example, we coded both URLs, but the SoapClient needs only the WSDL because there is an <address> tag that states the location of the service and that is an ideal place for this value.

We coded the URL for documentation purposes and, in a few lines of code, we have a working web service that returns a custom conversion rate between international currencies.

In the REST code, the SOAP-based web services URLs are highlighted in bold.

After selecting the from and to currencies, and entering an initial currency amount, the resulting window opens when you click Get Rate. Figure 5-40 shows the requested currency types, conversion rate, original amount, and new target currency amount.

PHP Currency Rate web service

Something practical

Having the ability to dynamically request currency codes is useful for the form population. In many accounting systems, there is usually a table in DB2 that is loaded “periodically” to reflect the currency codes rates because they tend to change daily. It can be helpful if the currency code values in the DB2 table can be updated by part of this PHP script process and then scheduled to run in batch. After the code is written to update the DB2 table, the batch submission can be achieved two ways: the first is with a CL program calling the PHP script in Call Level Interface mode, and the second is by using a premium feature of Zend Server called job queue or by using a CL program and php-cli.

The last function in the example application is tied to the Load Rate button and reads through the DB2 table and calls the web service once for each record in the combination of currency codes. The update statement replaces the previous value of the currency code, and you see an example of how to update a DB2 Date field so that the table reflects the date of the last update. Here is the SQL to create the table:

CREATE TABLE ZENDDATA.RATES (FROMCURRENCY CHAR (3 ) NOT NULL WITH
DEFAULT, TOCURRENCY CHAR (3 ) NOT NULL WITH DEFAULT, CONVERSIONRATE
FLOAT NOT NULL WITH DEFAULT, CONVERTDATE DATE NOT NULL WITH DEFAULT);

INSERT INTO ZENDDATA.RATES VALUES('USD', 'GBP', .5913, '01/02/2014')

After you call the PHP script, the new values are displayed for the currency types:

Showing the updated currency values after the web services calls
{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>