Create Multi-Mobile Applications with PHP

What is a Multi-Mobile Application?

The typical job description in the technology industry doesn’t include hazardous duty pay for all of the annoying acronyms, buzzwords and overhyped slogans that get tossed around. As such, I’m always cautious about using a new one (yes, I still feel a little funny talking about AJAX). However, I have noticed a trend toward a new type of web application that is focused on the delivery of content and interactivity to end users through multiple devices (desktop browser, cell phone, traditional phone, PDA, IM client, etc.). This new breed of application, in my humble opinion, deserves its own buzzword — “Multi-mobile” applications.

Fans of XHTML+Voice and SALT will know instantly what multimodal applications are — applications that support different kinds of user input (i.e., voice, keypad, stylus) through the same interface. Multi-mobile applications are differnet. These applications deliver content that is specifically tailored to the device being employed by the end user. This content is formatted differently based on the requirements of each specific device, and the mode of input is restricted to that supported by the device. Users accessing a form requiring specific input will see different manifestations of the same interface depending on the device they are using. What makes these applications special is that a single code base provides the functionality for device independence. So, whether an end user is making a phone call, using a WAP-enabled browser or an XHTML-enabled PDA the application is built to format an interface appropriately for each device.

I think this is a pretty cool concept, one worthy of its own buzzword. Besides, describing this approach to application design literally — “parallel mono-modality” — doesn’t do it justice in my opinion (needs more zing!).

Building Multi-Mobile Applications

One of the most convenient and powerful ways for building multi-mobile applications that I have come across is a PHP class library called HAWHAW (HTML and WML Hybrid Adapted Webserver). The HAWHAW toolkit actually has two additional elements — HAWHAW XML (an XML-based markup language for creating mobile applications) and HAWXY (a proxy server written in PHP for precessing HAWHAW XML). I’ll be focusing on the HAWHAW PHP class library in this example.

The HAWHAW class library comes with an excellent tutorial and a very detailed set of documentation. Once I downloaded this library and began playing with it, I was able to create cross-platform multi-mobile applications in a very short period of time. To demonstrate how easy it is to use this tool, lets take an example that could apply to a number of different government entities — utility meter reading.

This issue is on my mind lately because I came home from the office recently to find that I had missed the monthly visit from the meter reader and instead had been given one of those blank forms to fill out after examining the water meter in my basement. The way my local government approaches this issue is to let customers self report their meter readings using a phone-in service (a very clunky sounding old IVR system). Lots of other municipalities use web-forms to allow customers to self report. And even though many municipalities and utilities are moving toward Automated Meter Reading (where a special meter installed in customer homes emits a radio signal that is picked up by passing meter readers), customer self reporting is bound be to be a common way to get customer meter readings for a while.

A Multi-Mobile Meter Reading Application

This example assumes that you have downloaded the HAWHAW PHP class library and installed it on a PHP-enabled web server and have familiarized yourself with the documentation. I’d also reccomend becoming familiar with some of the general concepts of Wireless Markup Language (WML) applications development — HAWHAW was originally created to serve up WML content, so it will help if you have a basic understanding of decks and cards as they are used in the world of WML.

  • To test the application disucssed here, point your desktop browser, micro browser, PDA, WAP-enabled cell phone, etc. here.
  • To test the VoiceXML version of this application, use your VoIP phone to call SIP:9991421352@sip.voxeo.net.

document.hawform.callbutton.value = ” Make SkypeOut call NOW!!! “;

We begin our application by including the required HAWHAW class and setting up a deck:

// Include class to generate output
require('path_to_hawhaw/hawhaw.inc.php');

// Create page an use simulator to test and debug
$page = new HAW_deck(“Submit Your Meter Reading“);
$page->use_simulator();

Calling the use_simulator() method allows users to view HAWHAW applications as they might appear in a mobile device by using a standard desktop browser. (You can still view HAWHAW applications using a traditional desktop browser without calling this method, but the application will return a simple HTML interface.)

Now lets create a form with input items for entering a meter reading, and then generate a page:

// Create a new form to enter a meter reading
$form = new HAW_form(“meterSubmit.php“);

// Create a submit button for the form
$submit = new HAW_submit(“Submit“);

$input1 = new HAW_input(“account_num“, ““, “Account Number:“);
$input1->set_size(6);
$input1->set_maxlength(6);
$input1->set_voice_text(“Please enter your 6 digit account number.“);
$input1->set_voice_type(“digits?length=6“);
$input1->set_br(2);

$input2 = new HAW_input(“reading“, ““, “Meter Reading:“);
$input2->set_size(8);
$input2->set_maxlength(8);
$input2->set_voice_text(“Please enter your 8 digit meter reading.“);
$input2->set_voice_type(“digits?length=8“);
$input2->set_br(1);

// Add input items and submit button to form
$form->add_input($input1);
$form->add_input($input2);
$form->add_submit($submit);

// Add form to page
$page->add_form($form);

// Render the page
$page->create_page();

You can see where I have called the appropriate methods on the HAW_input objects to style them for different types of user agents. Each of my two HAW_input objects has a maximum character length set, and each has a line break or two that follow them. I’ve also called the set_voice_text() and set_voice_type() methods on these objects to give them the features they will need to work properly on a VoiceXML platform. From a VoiceXML perspective, you can think of these input objects as <field> elements. These methods set the field prompt and field type respectively. Note that in calling the set_voice_type() method, I’ve set a length for each field — if an input string of a different length is used, the VoiceXML platform will throw a nomatch event to be caught by the appropriate handler.

Speaking of event handlers, you may be wondering how to set up special prompts when noinput or nomatch events occur. HAWHAW has a number of different methods for setting up these specific event handlers, and a lot more. A good deal of thought has gone into rendering VoiceXML markup through HAWHAW, and the project creator (Norbert Huffschmid) is to be commended for this excellent work. I’m going to hold off on setting up noinput and nomatch handlers for now, because I want to take a slightly different approach than what is currently supported in the HAWHAW library.

To finish out our example, we need to post the user input back to our server and take the user to another HAWHAW deck object. In a production application, this posting would probably involve validating the user input and querying an account database. For this example, we’ll keep it simple. (Note — the parameter used when creating a new HAW_form object is the URL that the user input is posted to — in this example, a file called “meterSubmit.php“. Lets look at that file now:

require('path_to_hawhaw/hawhaw.inc.php');
$page = new HAW_deck(“Submission Result“, HAW_ALIGN_CENTER);
$page->use_simulator();

// Create short variable names for form input variables
$account = trim(addslashes($_REQUEST['account_num']));
$reading = trim(addslashes($_REQUEST['reading']));


// Check for errors in user input
if (!$account || !$reading) {
$error_text1 = new HAW_text(“You must enter both your account number and meter reading.“);
$error_text1->set_br(2);
//$error_text1->set_voice_text(“You must enter both your account number and meter reading.“);
$link = new HAW_link(“Try Again“,“meterReading.php“);
$page->add_text($error_text1);
$page->add_link($link);
$page->create_page();
die;
}

if (strlen($account)!=6) {
$error_text2 = new HAW_text(“You must enter your 6 digit account number.“);
$error_text2->set_br(2);
//$error_text2->set_voice_text(“You must enter your 6 digit account number.“);
$link = new HAW_link(“Try Again“,“meterReading.php“);
$page->add_text($error_text2);
$page->add_link($link);
$page->create_page();
die;
}

if (strlen($reading)!=8) {
$error_text3 = new HAW_text(“You must enter your 8 digit meter reading.“);
$error_text3->set_br(2);
//$error_text3->set_voice_text(“You must enter your 8 digit meter reading.“);
$link = new HAW_link(“Try Again“,“meterReading.php“);
$page->add_text($error_text3);
$page->add_link($link);
$page->create_page();
die;
}

// Display results
$text1 = new HAW_text(“Account #: $account“);
$text1->set_br(2);
$text1->set_voice_text(“You entered account number, $account“);

$text2 = new HAW_text(“Reading: $reading“);
$text2->set_br(2);
$text2->set_voice_text(“You entered a reading of, $reading“);

$text3 = new HAW_text(“Thank you!“);
$text3->set_voice_text(“Thank you.“);

$page->add_text($text1);
$page->add_text($text2);
$page->add_text($text3);

$page->create_page();

Pretty straightforward — there is probably a much more efficient way to validate the user input, but for the purposes of illustration I thought I’d focus on clarity rather than efficiency. Notice that I have commented out the text to be used on a voice platform when incomplete input is submitted. This is because it should never be needed. Remember, we parametrized our voice fields in the previous file by requiring a specific number of digits as valid input — set_voice_type(“digits?length=8“). When a field with this type is visited by the Form Interpretation Algorithm (FIA) on a VoiceXML platform, a string of digits with the appropriate length must be entered, otherwise a nomatch event will be thrown and the FIA will revisit this field until it is successfully filled (or until a nomatch event handler specifies different behavior, like transferring a caller to a customer service representative). Therefore, on a voice platform a caller should never encounter the page “meterSubmit.php“ until both fields on the preceding page are filled with input of the appropriate length.

Clearly in production this part of the application would be much more sophisticated, but this is sufficient to illustrate the basic steps involved.

One Step Beyond, Modifying the HAWHAW Class Library

As powerful and as useful as this tool is, it does have its limitations. Most are inherent in the nature of developing interfaces for multiple end user devices. Because this tool needs to generate markup for a large number of user agents, many of which have character and space limitations (the HAWHAW documentation notes that “a lot of older WAP devices can not handle more than about 1,400 bytes of compiled data.“) it pays to keep the interface simple.

Moreover, because this tool was initially developed with the goal of generating WML pages there are some aspects of VoiceXML application development that are missing. For example, what if we wanted to set up an event handler with application scope that was specially tailored for callers having problems using the application. We may want to transfer such callers to a customer service agent so that they could get the help they need to submit their meter readings. Such an event handler might look like the following:

<noinput count=“3“>
<goto next=“#transfer“/>
</noinput>

<!-- Form for transferring callers that are having trouble -->
<form id=“transfer“>
<block>
<prompt>Please hold a moment.  I'll transfer you to a customer service representative.</prompt>
</block>
<transfer name=“tran1“ bridge=“true“ connecttimeout=“20s“ dest=“tel:+12223334444“>
 <filled>
  <if cond=“tran1 == 'busy'“>
  <prompt>The line is busy.  Please try back later.</prompt>
  <exit/>
 <elseif cond=“tran1 == 'noanswer'“/>
  <prompt>No one is available to take your call right now.  Please try back later.</prompt>
  <exit/>
 </if>
</filled>
</transfer>
</form>

We might also want to capture the phone number of the caller, and set up a custom event handler to catch application errors, or to detect when a caller has become frustrated and hangs up:

<!-- Capture caller ANI -->
<var name=“ani“ expr=“session.telephone.ani“/>

<catch event=“connection.disconnect.hangup“>
  <var name=“errType“ expr=“_event“/>
   <submit next=“error.php“ namelist=“ani errType“/>
  <exit/>
</catch>

The way that I do this in my VoiceXML applications is to create an application root document, and then reference that root document in successive VoiceXML pages. There isn’t a way to do this currently in HAWHAW, but with some minor tweaks, we can add some new functionality to allow this. You can obtain a modified version of HAWHAW (along with a description of the changes) by clicking here. Note, this isn’t the official version of this tool, but one of the nice things about open source software is that you can modify it to meet your needs. Hopefully you will find this helpful — if not, the official version of this tool can be downloaded from the HAWHAW website.

So, with our modified version, we would change the approach outlined above to set our application root document when creating a HAW_deck object.

// Include class to generate output
require('pathtohawhaw/hawhaw.inc.php');

// Create page an use simulator to test and debug
$page = new HAW_deck(“Submit Your Meter Reading“);
$page->use_simulator();

// Set application root for VoiceXML output
$page->set_application(“appRoot.vxml“);

I put all of my application-scoped variables and event handlers in a file called “appRoot.vxml“ and pass the name of this file as a parameter when calling the new set_application() method. Now, when HAWHAW outputs VoiceXML, there will be a reference to this root document and the variables and event handlers I have set up will be available from within my HAWHAW pages.

A quick deployment note, when setting up a VoiceXML platform to support this application, it needs to point to the “appRoot.vxml“ file, not to the initial HAWHAW page. Users with other mobile devices will access the the HAWHAW pages directly. This may add an additional level of complexity, but since users accessing the application via phone will be calling a telephone number (not accessing a URL) its not likely to be confusing.

Although this approach is not supported in the official version of HAWHAW, I find it more conveneint for some of the very specific behavioral features I typically put in my VoiceXML applications. The fact that users can also access my application on a mobile device or PDA is icing on the cake!

Conclusion

You can obtain all of the code discussed above by clicking here.

Hopefully, this brief introduction will get you thinking about building multi-mobile applications. I hope that it also gets you excited about the power of PHP generally and HAWHAW specifically for creating such applications. I have run the application described here on both Windows and Linux under PHP 4.3.x and 5.0 without issue.

If that can’t get you excited then perhaps there is a need for another new buzzword to describe your current state. I suggest CUDDLE (Confused, Unusually Down and Depressed and Lacking Excitement). 😉

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.