http://www.developer.com/

Back to article

Learning WML -Scripting Tips And Integration With PHP


August 30, 2002

Project Description

In our last article we implemented a simple phone list using PHP and MySQL. The basic premise was to give salespeople access to a central contact database without the need of synchronizing their phones/PDAs. The script pulled contact data from a database, displayed the records, and dialed the selected record. This project will expand on that example, adding the following features:

  • The contact database will include address information.
  • There will be more contacts, requiring the list to be displayed a few records at a time.
  • A search feature will be added.

Because there will be more than one feature (list and search), we will also need a menu so the user can choose what feature he or she wants. Each screen will also need a way to return to the menu.

PHP Script Outline

The project will use one PHP script and a controlling variable ($cmd) that tells the script card that it is supposed to display. The script recursively calls itself with the proper value of $cmd, matching the function it is supposed to perform next. The script's functionality resembles the following:

   If $cmd is empty, set it to "Menu"

   If $cmd is set to "Menu," display the Menu card
   If $cmd is set to "List," display the List card
   If $cmd is set to "Display," 
         display the Display card, with the appropriate record
   If $cmd is set to "Search," display the Search card
   
   When a function is chosen, 
        set $cmd appropriately and recursively call self.

The search function will search through the database looking for first or last names that meet the text entered in the search card. The list function will display five records at a time and will include options for moving to the next set of five records or returning to the home menu. Each option (record or link) will have a quick key. Essentially, the list will resemble the following:

  1. <DB record>
  2. <DB record>
  3. <DB record>
  4. <DB record>
  5. <DB record>
  6. [Next 5 link]
  7. [Home link]

Selecting a record results in displaying all of the data associated with the record, along with "dial" and "home" links.

The Contact List

Our contact database will contain the following data:

 

First
Name

Last
Name

Phone

Address

City

State

Zip

Last
Update

Jack

Hampton

317-555-2200

213 Main St

Indianapolis

IN

46222

2002-08-22

Samuel

Marks

317-555-8764

2 Northridge Dr

Fishers

IN

46203

2002-08-22

Sally

Nash

317-555-8765

644 Innovation Pl

Ft Wayne

IN

46875

2002-08-22

Bill

Haskins

317-555-8766

201 W 103rd

Indianapolis

IN

46240

2002-08-24

Jill

Payton

317-555-0098

55 W 96th St

Westfield

IN

46222

2002-08-22

Mary

Martinez

317-555-7544

9433 E. 75th Ave

Greenwood

IN

46784

2002-08-22

Ned

Tanner

317-555-9877

77 E Marchen

Ft Wayne

IN

46875

2002-08-23

Bruce

Wilten

317-555-1111

3 Prospect

Indianapolis

IN

46038

2002-08-22

Naomi

Waters

317-555-4323

1121 Central Pl

Westfield

IN

46055

2002-08-22

Angela

Renault

317-555-0988

5674 E 6th Ave

Noblesville

IN

46234

2002-08-22

Markus

Elliot

317-555-3232

9755 Carter

Indianapolis

IN

46250

2002-08-22

Steve

Albert

317-555-5444

95 Crescent Dr

Indianapolis

IN

46250

2002-08-26

Martin

Rolfsen

317-555-6767

5678 E 7th Ave

Indianapolis

IN

46234

2002-08-22

Lisa

Biggins

317-555-3644

7732 Allisonville

Indianapolis

IN

46240

2002-08-22

Eric

Gonday

317-555-0500

9466 Pike Plaza

Greenfield

IN

46533

2002-08-22

Douglas

Poser

317-555-0123

55 Tower Pl

Noblesville

IN

46234

2002-08-24

John

Palmer

317-555-4444

12433 N Cumberland

Fishers

IN

46038

2002-08-22

The database will also contain an "ID" field as a primary key (integer). That will serve as a unique key into each record. To create the data in MySQL, the following commands should be used:

CREATE DATABASE customers;

USE customers;

CREATE TABLE Phone (
  Id int(11) NOT NULL auto_increment,
  FirstName varchar(30) default NULL,
  LastName varchar(30) default NULL,
  Phone varchar(12) default NULL,
  Address varchar(30) default NULL,
  City varchar(30) default NULL,
  State char(2) default NULL,
  Zip varchar(5) default NULL,
  LastUpdate date default NULL,
  PRIMARY KEY  (Id)
) TYPE=MyISAM;

INSERT INTO Phone VALUES (1,'Jack','Hampton','317-555-2200',
'213 Main St','Indianapolis','IN','46222','2002-08-22');
INSERT INTO Phone VALUES (2,'Samuel','Marks','317-555-8764',
'2 Northridge Dr','Fishers','IN','46203','2002-08-22');
INSERT INTO Phone VALUES (3,'Sally','Nash','317-555-8765',
'644 Innovation Pl','Ft Wayne','IN','46875','2002-08-22');
INSERT INTO Phone VALUES (4,'Bill','Haskins','317-555-8766',
'201 W 103rd','Indianapolis','IN','46240','2002-08-24');
INSERT INTO Phone VALUES (5,'Jill','Payton','317-555-0098',
'55 W 96th St','Westfield','IN','46222','2002-08-22');
INSERT INTO Phone VALUES (6,'Mary','Martinez','317-555-7544',
'9433 E 75th Ave','Greenwood','IN','46784','2002-08-22');
INSERT INTO Phone VALUES (7,'Ned','Tanner','317-555-9877',
'77 E Marchen','Ft Wayne','IN','46875','2002-08-23');
INSERT INTO Phone VALUES (8,'Bruce','Wilten','317-555-1111',
'3 Prospect','Indianapolis','IN','46038','2002-08-22');
INSERT INTO Phone VALUES (9,'Naomi','Waters','317-555-4323',
'1121 Central Pl','Westfield','IN','46055','2002-08-22');
INSERT INTO Phone VALUES (10,'Angela','Renault','317-555-0988',
'5674 E 6th Ave','Noblesville','IN','46234','2002-08-22');
INSERT INTO Phone VALUES (11,'Markus','Elliot','317-555-3232',
'9755 Carter','Indianapolis','IN','46250','2002-08-22');
INSERT INTO Phone VALUES (12,'Steve','Albert','317-555-5444',
'95 Crescent Dr','Indianapolis','IN','46250','2002-08-26');
INSERT INTO Phone VALUES (13,'Martin','Rolfsen','317-555-6767',
'5678 E 7th Ave','Indianapolis','IN','46234','2002-08-22');
INSERT INTO Phone VALUES (14,'Lisa','Biggins','317-555-3644',
'7732 Allisonville','Indianapolis','IN','46240','2002-08-22');
INSERT INTO Phone VALUES (15,'Eric','Gonday','317-555-0500',
'9466 Pike Plaza','Greenfield','IN','46533','2002-08-22');
INSERT INTO Phone VALUES (16,'Douglas','Poser','317-555-0123',
'55 Tower Pl','Noblesville','IN','46234','2002-08-24');
INSERT INTO Phone VALUES (17,'John','Palmer','317-555-4444',
'12433 N Cumberland','Fishers','IN','46038','2002-08-22');

The Cards

The following sections list the PHP code used for each function/card. Note that the WML and header code is taken care of by global statements-each card need only output the <card> tags and everything in-between. The $cmd variable controls what function is executed, and hence, which card is displayed.

Note: I've used "echo" commands in this script, but "print" commands would do just as well. Also, to increase the readability of the output I've added line feeds (via a variable, $lf, set to ASCII character 10) to most lines of output. I've chosen to append this variable to the "echo" statements for readability purposes--using "\n" in your "echo" commands would do just as well but tends to clutter the information between the quotes. Also note the use of the entity "&amp;" in the URLs instead of a straight ampersand ("&"). This is necessary to keep WML from assuming that the ampersand is the beginning of an entity name.

Menu

The menu function displays a simple select list, allowing the user to choose what function he or she wants to access:

  echo "<card id=\"Menu\">\n";
  echo "<p mode=\"nowrap\">".$lf;
  
  // Set up Select menu list 
  echo "<select name=\"Select\" title=\"Select:\">".$lf;

  // Go through results from Query, listing each as a CHOICE entry
  echo "<option onpick=\"?cmd=List\">";
  echo "List Contacts</option>".$lf;
  echo "<option onpick=\"?cmd=Search\">";
  echo "Search Contacts</option>".$lf;
  
  // Close select
  echo "</select>".$lf;

  // Close card
  echo "</p>".$lf."</card>".$lf;

The code is straightforward, defining a simple <select> list. Each <option> in the list calls the current script, passing the appropriate value of $cmd. Note that we need to handle the case when $cmd is empty, which it will be when the script is first called. In the body, near the beginning of the script, we add the following line:

  if (empty($cmd)) { $cmd = "Menu"; }

That ensures that if no command is given (via $cmd), the menu will be displayed.

List

This is the meat of the script, displaying both the raw list as well as search results, five records at a time. (For reference after the listing, each line has been numbered.)

1  // Construct appropriate *count* query
2:   $query = "select count(*) from Phone";
3:   if (!empty($search)) {
4:     $query = $query." where FirstName like \"%".$search."%\" or";
5:     $query = $query." LastName like \"%".$search."%\"";
6:   }

7:   $result = mysql_query($query,$link)
8:     or die("Query failed:$query");

9:   list($total_rows) = mysql_fetch_array($result);

10:   // Construct appropriate query
11:   $query = "select * from Phone";
12:   if (!empty($search)) {
13:     $query = $query." where FirstName like \"%".$search."%\" or";
14:     $query = $query." LastName like \"%".$search."%\"";
15:   }

16:   // Get first/next five records
17:   $query = $query." order by LastName limit ".$idx.",5";

18:   $result = mysql_query($query,$link)
19:     or die("Query failed:$query");

20:   // Advance DB index
21:   $next = $idx + 5;

22:   // Start card
23:   echo "<card id=\"Contacts\">\n";
24:   echo "<do type=\"accept\" label=\"View\"> <go href=\"\"/> </do>".$lf;

25:   // Display appropriate full/search heading
26:   if (empty($search)) {
27:     echo "<p mode=\"nowrap\"><b>Phone Book</b>".$lf;
28:   } else {
29:     echo "<p mode=\"nowrap\"><b>Search Results</b>".$lf;
30:   }

31:   // Set up Select list (list of five records)
32:   echo "<select name=\"View\" title=\"View:\">".$lf;

33:   // Go through results from Query, listing each as a CHOICE entry
34:   while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {

35:     $recordid = $line[Id]; 
36:     $Name = $line[LastName] . ", " . $line[FirstName];
37:     $Number = $line[Phone];
38:     $Prompt = $Name . " (" . $Number . ")";

39:   // Build URL for option, include DB index and search
40:     $option = "<option onpick=\"";
41:     $option = $option."?cmd=Display&amp;id=".$recordid."&amp";
42:     $option =
   $option.";idx=".$recordid."&amp;search=".$search."\">";
43:     $option = $option.$Prompt."</option>".$lf;
44:     echo $option.$lf;

45:   }

46:   // If there are more records to display, set up paging
47:   //   else mark end of list (to keep Home as same option)
48:   if ($total_rows >= $next) {

49:   // Link to next five
50:     echo "<option title=\"Next\" onpick=\"?cmd=List&amp;idx=$next";

51:   // Pass Search criteria if exists
52:     if (!empty($search)) {
53:       echo "&amp;search=".$search;
54:     }

55:     echo "\">[Next Records]".$lf."</option>".$lf;

56:   } else {

57:     echo "<option title=\"End of List\" onpick=\"?cmd=List&amp;idx=$idx";

58:   // Pass Search criteria if exists
59:     if (!empty($search)) {
60:     echo "&amp;search=".$search;
61:     }

62:   // Close tags
63:     echo "\">[End of List]".$lf."</option>".$lf;

64:   }          

65:   // Add option for Home
66:   echo "<option onpick=\"?cmd=Menu\" title=\"Home\">".$lf;
67:   echo "[Back to Home]".$lf;
68:   echo "</option>".$lf;

69:   // Close select
70:   echo "</select>".$lf;

71:   // Close card
72:   echo "</p>".$lf."</card>".$lf;

This code makes use of global variables ($idx, $search) to display the list of contacts. Both variables are passed as a name/value pair when the script is called with $cmd equal to "List." If $search is empty, the full list of contacts is displayed, else the text of $search is added to the query and records are returned only if FirstName or LastName contains the search text.

The $idx variable marks what results the script currently is listing. The record at location $idx is the first record on the current page.

This becomes more self-explanatory as we work through the code:

Lines 1-9 construct and execute a "count" query, storing the number of returned rows in the variable $total_rows. This value is used later (line 48) to determine whether there are more pages of data to display. Note that the search text is added if $search is not empty (hence contains search criteria).

Lines 10-19 construct a query to return the target dataset. Again, the search criterion is added to the query, if it exists. Line 17 appends a limit clause to the query, causing the query to return only five records (or less), starting at the record indicated by the value of $idx. If $idx is zero (which it will be the first time the script executes List), the first five records are returned. The variable $next is set to a value of $idx + 5 (line 21) and used to call the next iteration of List, causing the next five records to be displayed.

Note: This method is far from perfect. For example, if a record is added or modified that causes a record to be added or removed from the returned dataset, the next page will return different results than it would before the record was added or modified. If the list is being displayed while the records are being modified-which happens in most database applications-the displayed results can be somewhat unpredictable.

Lines 22-30 begin the display card definition, including the appropriate header-"Phone Book" if the search string is empty (raw list being displayed) or "Search Results" if the search string is not empty (search results being displayed). This helps guarantee that the result set returned will be the same, allowing consistent paging through the set (with the caveat explained above).

Line 32 begins the <select> list, with lines 34-70 building and displaying five items as <option>s. Lines 35-38 build the text for the <option> prompt, while lines 39-44 construct the <option> statement with an appropriate "onpick" parameter that recursively calls the script with $cmd equal to "Display" and the ID of the record to display. Note that $idx and $search are also passed to maintain their values through the recursive call, just in case we need them later.

Lines 49-64 build option number 6 in our select list. If there are more records to display ($total_rows >= $next) the script generates the option "[Next Records]" with an appropriate "onpick" parameter to recursively call the script, specifying the next starting record to display (via idx=$next). If there are no more records to display, the script generates an "[End of List]" option, which recursively calls the script with the same starting point as is currently displayed. Each option also includes the search criteria if it exists (lines 51-54 and 58-61).

Finally, a "Home" option is created (lines 65-68) to allow the user to return to the home menu from any page of the listing. The open tags are then closed.

Search

The search function is simply an input tag that accepts up to 10 characters and recursively calls the script supplying the text entered and sets $cmd equal to "List."

  echo "<card id=\"Search\">\n";
  echo "<do type=\"accept\" label=\"Go\">".$lf;
  echo "<go href=\"?cmd=List&amp;search=\$searchtext\">".$lf;
  echo "</go>".$lf;
  echo "</do>".$lf;

  echo "<p>".$lf;
  echo "<b>Phone Book Search</b><br/>Search for:".$lf;
  echo "<input name=\"searchtext\" title=\"Search\" type=\"text\"";
  echo "  format=\"10m\"/>";
  echo "</p>".$lf;
  echo "</card>".$lf;

Display

Display uses the record ID passed in $idx to select a record from the database and display all of its related information (name, address, phone, etc.).

  echo "<card>\n";
  
  // Get specific record
  $query = "select * from Phone where Id = \"".$idx."\"";
  
  $result = mysql_query($query,$link)
    or die("Query failed:$query");
  
  // Get data and display
  while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
    $recordid = $line[Idx];

    echo "<p mode=\"wrap\">".$lf;
    echo "$line[LastName], $line[FirstName]<br />".$lf;
    echo "$line[Address]<br />".$lf;
    echo "$line[City], $line[State]  $line[Zip]<br />".$lf;
    echo "<a href=\"wtai://wp/mc;$line[Phone]\" title=\"Dial\">";
    echo "$line[Phone]</a><br />".$lf;
    echo "<a href=\"?cmd=Menu\" title=\"Menu\">";
    echo "[Home Menu]</a><br /><br />".$lf;

    $Date = date("M j, Y", strtotime($line[LastUpdate]));
    echo "Record Updated:<br />$Date";
    
    // Close record display card
    echo $lf."</p></card>".$lf;
    
  }

Note that the card has a "Dial" option mapped to the Accept key and is displayed with the phone number highlighted. This allows the user to quickly dial the selected number on devices that support URL dialing. Other items of note include a "Home Menu" link and a more verbose format for the last update date. We do not need to provide any functionality to return to the last page of record listings-the user can do so by pressing the Back key on his or her device.

The Entire Script

Now that we've defined the various functions of the script, let's tie it all together with a "switch" statement and some additional initialization statements:

<?php

header("Content-type: text/vnd.wap.wml");  

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");              
// expires in the past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");   
// Last modified, right now
header("Cache-Control: no-cache, must-revalidate");              
// Prevent caching, HTTP/1.1
header("Pragma: no-cache");                                
// Prevent caching, HTTP/1.0

echo "<?xml version=\"1.0\"?>\n";  
echo "<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\""  
   . " \"http://www.wapforum.org/DTD/wml_1.1.xml\">\n"; 
echo "<wml>\n";

// Open link to DB
$link = mysql_connect("localhost", "webuser", "webby99")
  or die("Could not connect to database!");
mysql_select_db("customers")
  or die("Could not select database!");

// Line feed
$lf = chr(10);

// Make sure that index into DB has value
if (empty($idx)) { $idx = 0; }

if (empty($cmd)) { $cmd = "Menu"; }

switch ($cmd) {

   case "Menu";

      echo "<card id=\"Menu\">\n";
      echo "<p mode=\"nowrap\">".$lf;
      
      // Set up Select menu list 
      echo "<select name=\"Select\" title=\"Select:\">".$lf;

      // Go through results from Query, listing each as a CHOICE entry
      echo "<option onpick=\"?cmd=List\">";
      echo "List Contacts</option>".$lf;
      echo "<option onpick=\"?cmd=Search\">";
      echo "Search Contacts</option>".$lf;
      
      // Close select
      echo "</select>".$lf;

      // Close card
      echo "</p>".$lf."</card>".$lf;

   break;

   case "List";

      // Construct appropriate *count* query
      $query = "select count(*) from Phone";
      if (!empty($search)) {
         $query = $query." where FirstName like \"%".$search."%\" or";
         $query = $query." LastName like \"%".$search."%\"";
      }

      $result = mysql_query($query,$link)
        or die("Query failed:$query");

      list($total_rows) = mysql_fetch_array($result);

      // Construct appropriate query
      $query = "select * from Phone";
      if (!empty($search)) {
         $query = $query." where FirstName like \"%".$search."%\" or";
         $query = $query." LastName like \"%".$search."%\"";
      }

      // Get first/next five records
      $query = $query." order by LastName limit ".$idx.",5";

      $result = mysql_query($query,$link)
        or die("Query failed:$query");

      // Advance DB index
      $next = $idx + 5;
      
      // Start card
      echo "<card id=\"Contacts\">\n";
      echo "<do type=\"accept\" label=\"View\"> <go href=\"\"/> </do>".$lf;
      
      // Display appropriate full/search heading
      if (empty($search)) {
         echo "<p mode=\"nowrap\"><b>Phone Book</b>".$lf;
      } else {
         echo "<p mode=\"nowrap\"><b>Search Results</b>".$lf;
      }
      
      // Set up Select list (list of five records)
      echo "<select name=\"View\" title=\"View:\">".$lf;

      // Go through results from Query, listing each as a CHOICE entry
      while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {

        $recordid = $line[Id]; 
        $Name = $line[LastName] . ", " . $line[FirstName];
        $Number = $line[Phone];
        $Prompt = $Name . " (" . $Number . ")";

        // Build URL for option, include DB index and search
        $option = "<option onpick=\"";
        $option = $option."?cmd=Display&amp;id=".$recordid."&amp";
        $option = $option.";idx=".$recordid."&amp;search=".$search."\">";
        $option = $option.$Prompt."</option>".$lf;
        echo $option.$lf;

      }

      // If there are more records to display, set up paging
      //   else mark end of list (to keep Home as same option)
      if ($total_rows >= $next) {

         // Link to next five
         echo "<option title=\"Next\" onpick=\"?cmd=List&amp;idx=$next";

         // Pass Search criteria if exists
         if (!empty($search)) {
            echo "&amp;search=".$search;
         }

         echo "\">[Next Records]".$lf."</option>".$lf;
         
      } else {
      
         echo "<option title=\"End of List\" onpick=\"?cmd=List&amp;idx=$idx";
         
         // Pass Search criteria if exists
         if (!empty($search)) {
            echo "&amp;search=".$search;
         }

         // Close tags
         echo "\">[End of List]".$lf."</option>".$lf;
         
      }         

      // Add option for Home
      echo "<option onpick=\"?cmd=Menu\" title=\"Home\">".$lf;
      echo "[Back to Home]".$lf;
      echo "</option>".$lf;

      // Close select
      echo "</select>".$lf;

      // Close card
      echo "</p>".$lf."</card>".$lf;
      
   break;
   
   
   case "Search";
   
      echo "<card id=\"Search\">\n";
      echo "<do type=\"accept\" label=\"Go\">".$lf;
      echo "<go href=\"?cmd=List&amp;search=\$searchtext\">".$lf;
      echo "</go>".$lf;
      echo "</do>".$lf;

      echo "<p>".$lf;
      echo "<b>Phone Book Search</b><br/>Search for:".$lf;
      echo "<input name=\"searchtext\" title=\"Search\" type=\"text\"";
      echo "  format=\"10m\"/>";
      echo "</p>".$lf;
      echo "</card>".$lf;
   
   break;
   
   
   case "Display";
   
      echo "<card>\n";
      
      // Get specific record
      $query = "select * from Phone where Id = \"".$idx."\"";
      
      $result = mysql_query($query,$link)
        or die("Query failed:$query");
   
      // Get data and display
      while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
        $recordid = $line[Idx];

        echo "<p mode=\"wrap\">".$lf;
        echo "$line[LastName], $line[FirstName]<br />".$lf;
        echo "$line[Address]<br />".$lf;
        echo "$line[City], $line[State]  $line[Zip]<br />".$lf;
        echo "<a href=\"wtai://wp/mc;$line[Phone]\" title=\"Dial\">";
        echo "$line[Phone]</a><br />".$lf;
        echo "<a href=\"?cmd=Menu\" title=\"Menu\">";
        echo "[Home Menu]</a><br /><br />".$lf;

        $Date = date("M j, Y", strtotime($line[LastUpdate]));
        echo "Record Updated:<br />$Date";
        
        // Close record display card
        echo $lf."</p></card>".$lf;
        
      }

   
   break;
   
}

echo $lf."</wml>".$lf;

mysql_close($link);

?>

Note that we pass a handful of headers at the beginning of the script to inhibit caching. Since our database is frequently updated and correct/up-to-date information in the field is valuable, we do not want the device to display cached information instead of recently updated information. However, generally speaking, inhibiting the cache is a bad idea and should be done sparingly, if at all.

The Script in Action

Now let's see the script in action. The following figures demonstrate each function:

Note: All images courtesy Openwave Systems Inc. (Openwave, the Openwave logo, Openwave SDK, Openwave SDK Universal Edition, Openwave SDK WAP Edition are trademarks of Openwave Systems Inc. All rights reserved.)

Figure 1 - The menu.

Figure 2 - The list. Notice the [Next Records] option.

Figure 3 - The end of the list. Notice the [End of List] option.

Figure 4 - The search form.

Figure 5 - The results of a search (for "in"). Note the first result is "Biggins, Lisa" but the text has scrolled to the phone number due to the "nowrap."

Figure 6 - A record in the display card.

Room for Improvement

This script has plenty of room for improvement, including the following items:

  • Applying the cache inhibitor headings only to cards that could cause problems (such as Display), instead of globally.
  • Optimizing the output to avoiding duplicating code (such as the addition of search criteria to the URL(s)).
  • Adding more prompts for the user through card titles, etc.
  • Optimizing and standardizing variable naming and usage.
  • Providing means for the user to edit records. Although it can be tedious to enter data on most mobile devices, simple corrections or notes would be welcome. A "last called" field could also be entered automatically each time a contact is called.

This script represents only a small portion of what can be done with PHP and a database such as MySQL. This example could be expanded to offer group calendaring, scheduling, order placement, stock checking, etc. As long as you keep the target audience and the respective design goals in mind, the sky's the limit.

About the Author

Steve Schafer is president and CEO of Progeny Linux Systems, a Linux-based consulting company in Indianapolis, Indiana. He has written several technical books and articles and can be reached at sschafer@synergy-tech.com.

About the "Learning WML" series...

This series of articles describes how to provide Web content to mobile devices through WML (Wireless Markup Language). This article covers advanced integration with PHP.

These articles cover WML and WMLScript version 1.1, which are supported by the majority of mobile devices in use today. The articles assume a working knowledge of HTML and general Web technologies, and further assume that you have read the previous article(s) in this series.

# # #

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date