Creating an online voting/polling system for WAP-enabled mobile devices using PHP/MySQL

Introduction

In this article, we step through the process of developping a simple dynamic WAP application, using mainly open source technologies. This application is a polling system, i.e. a system that lets visitors vote on a specific topic, or answer (using multiple choices forms) a specific question. It may be used, for example, to gain better understanding of some customers opinions. On a technical point of view, the features (questions, answers) and results of a poll are stored in a MySQL database, and the results can be displayed graphically in a bar charts way. Chosing the languages and softwares for this application was straightforward: PHP is quite well suited to building dynamic WAP applications (it is fast and has plenty of functions) and it has on the fly WBMP generation functions (by way of an external library). MySQL is also perfectly suited in this situation, since the  application is non critical (it does not require transactions), and it only uses simple "select", "insert" and "update" SQL queries. Besides, MySQL works quite well in conjunction with PHP. There are several things to consider, when developping WAP applications. Among them, there are:
- usability (navigation within WAP screens should be as intuitive as possible, information should be as concise as possible)
- deck size (the whole set of screens sent to a WAP browser), when compiled, cannot generally exceed 1.4Ko, otherwise the WAP gateway rejects it.
- speed: WAP is, at the moment, quite slow, so building dynamic pages should be very very fast.
- WML is not HTML: it follows the XML norm, therefore WAP browsers dot not allow ill-formed WML pages (for example, every opened tag such as <wml> should be closed somewhere with an </wml>).
General introductions and tutorials on building WAP applications with PHP can be found here and here
 

Requirements

First make sure you have PHP compiled with GD support, and that libgd is relatively recent (I used version 1.8.3, and I am not quite sure ealier versions offer WBMP support). If not, download libgd from http://www.boutell.com/gd, compile and install it on your system (that means compiling and copying libgd.a to /usr/local/lib or /usr/lib,and gd*.h to /usr/local/include or /usr/include). If you have not yet installed PHP from sources, download it from http://www.php.net, uncompress and untar the archive, cd to the php4.0.x directory and type the following commands to build and install PHP with mysql and GD support:


./configure --with-apxs --with-mysql --with-gd
make
make install


Then restart your web server (apachectl restart is you use Apache). Finally, make sure that MySQL is installed on your system (installing MySQL is not part of this article).
 

Testing the application can obviously be done with a WAP phone. Since not everybody out there owns a WAP-enabled phone or PDA, and still needs to test its WAP applications, the best thing to do is to install a WAP browser emulator. There are not many WAP browsers running under Linux (the best WAP emulator I have used is part of the Windows Nokia SDK, it is written mostly in Java, but requires a few DLLs to function). Personally, I use the Deck-it previewer, available freely (it is not open source) at http://www.pyweb.com. Its best advantages are that it is quite fast, and it can display the WML code it receives.
 

Anatomy of the application

The application consists of 5 PHP files:
- config.inc.php, which contains the MySQL parameters and connection funtcions
- show_polls.php, which displays the question, and the possible choices
- vote_polls.php, which inserts the user's choices into the database
- show_results.php, displays the bar charts image
- show_image.php, which dynamically generates the WBMP image from the database data
 

Creating the database

The database consists of only two tables. The first one, called "polls" simply contains the questions corresponding to the different available polls. The second table, named "responses", contains the different choices for each poll, and the numbers of times visitors selected each possible responses. Here are the SQL commands needed to create the tables:



create table polls (
poll_id int not null auto_increment,
poll_question varchar(100),
primary key(poll_id)
);

create table responses (
response_id int not null auto_increment,
response_refpoll int,
response_string varchar(50),
response_nb int default 0,
primary key(response_id)
);


Once the table are created, they are populated with the following data. This poll basically ask visitors which Linux distributions they use, between Red Hat, Mandrake, etc...



insert into polls values (null, "Which Linux distribution do you use?");

insert into responses (response_refpoll, response_string) values (1, "Red Hat");
insert into responses (response_refpoll, response_string) values (1, "Mandrake");
insert into responses (response_refpoll, response_string) values (1, "TurboLinux");
insert into responses (response_refpoll, response_string) values (1, "Caldera");
insert into responses (response_refpoll, response_string) values (1, "SuSE");



 

Database parameters and connection

The following config.inc.php file contains code that create a (persistant) connection to the MySQL database, and selects the required database:



<?php

$host = "localhost";
$user = "root";
$password = "";
$database = "test";

$conn = mysql_pconnect($host,$user,$password);
if (!$conn)
{
  echo "Connection impossible\n";
  exit;
}

mysql_select_db($database);

?>


Dynamic creation of the poll

This is the WML code required to display a multiple selection list form:



<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
    <template>
    <do type="prev" label="Back">
       <prev/>
     </do>
     </template>

     <card id="MainCard" title="Polling system">
           <p>
                Which Linux distribution do you use?<br/>
                <select name="response" multiple="true">
                    <option value="1">Red Hat</option>
                    <option value="2">Mandrake</option>
                    <option value="3">TurboLinux</option>
                    <option value="4">Caldera</option>
                    <option value="5">SuSE</option>
                </select>

                <a href="vote_poll.php?poll=1&amp;response=$(response)">Vote now!</a><br/>
          </p>
    </card>

</wml>


The <select> tag implements a selection list form. Since the multiple attribute is set to true, several options can be selected simultaneously, and each <option> tag constitutes a possible choice. The variable called $(response) is filled with the "value" attributes of the selected options, separated by ";". For example, if the user selects both Red Hat (response=1) and Mandrake (response=2), $(response) will be filled with the string  "1;2".
The initial screen corresponding to this example is shown below:

Clicking on the [...] link (see above) prompts the following display:


 

Since all our polls are stored within the database, the following PHP script (PHP code is shown in blue) fetches information from the database, and create the appropriate WML code. You simply have to specify, when calling the script from your browser, which poll you want to display, for example: http://localhost/show_poll.php?poll=1

Here is the PHP code for show_poll.php:



<?php

include("config.inc.php");

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

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

?>

<wml>
    <template>
    <do type="prev" label="Back">
        <prev/>
    </do>
    </template>

    <card id="MainCard" title="Polling system">
    <p>

<?php

     //fetches the desired poll question
     $result = mysql_query("select poll_question from polls where poll_id = $poll") or die("There is something wrong the SQL query (" . mysql_error() . ")\n");

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

     print "$question<br/>\n";

     print "<select name=\"response\" multiple=\"true\">\n";
 
     //now fetches the possible answers
     $result = mysql_query("select response_id, response_string from responses where response_refpoll = $poll") or die("There is something wrong the SQL query (" . mysql_error() . ")\n");
     while (list($response_id, $response_string) = mysql_fetch_array($result)) {
         print "<option value=\"$response_id\">$response_string</option>\n";
     }

     print "</select>\n";
     print "<a href=\"vote_poll.php?poll=$poll&amp;response=$(response)\">Vote now!</a><br/>\n";

?>

    </p>
 

</card>

</wml>



 

Inserting the user's choices into the database

The following script (I called it vote_poll.php) inserts the selections into the database, and prints a link towards the result page:


<?php

include("config.inc.php");

//explode $response
$response_array = explode(";", $response);

//join the array with ',' for inclusion in the following sql query
$response_sql = join(",", $response_array);

//update the number of responses
mysql_query("update responses set response_nb = response_nb + 1  where response_id in ($response_sql)") or die("There is something wrong the SQL query (" . mysql_error() . ")\n");

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

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

<wml>
   <template>
   <do type="prev" label="Back">
       <prev/>
   </do>
   </template>

   <card id="MainCard" title="Polling system">
   <p>
  Thank you! See the results at this <a href="show_results.php?poll=<?php print $poll; ?>">page</a>.
   </p>
   </card>
</wml>


And the corresponding screen is:


 
 

Graphical results outputing


The "page" link shown above leads to a very simple WML page (show_results.php), which contains a dynamically generated WBMP image. The code for show_results.php is shown below:



<?php
header("Content-type: text/vnd.wap.wml");
print '<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">';
?>
<wml>

    <template>
        <do type="prev" label="Retour">
            <prev/>
        </do>
    </template>

    <card id="MainCard" title="Polling system">
        <p>
            <img src="show_image.php?poll=<?php print $poll; ?>" alt="WBMP image"/><br/>
        </p>
    </card>

</wml>



 

Here is the PHP code for show_image.php, the script that automatically generates the WBMP bar charts image from the results stored within the database. Note that the Content-type sent to the WAP browser is image/vnd.wap.wbmp.



<?php

include("config.inc.php");

$height = 50;
$width = 100;

//initialize the array
$responses = array();
$responses_strings = array();

//exec the sql query that retrives results of the desired poll
$result = mysql_query("select response_string, response_nb from responses where response_refpoll = $poll") or die("There is something wrong the SQL query (" . mysql_error() . ")\n");

//store the results into the array
while (list($response_string, $response_nb) = mysql_fetch_array($result)) {
    $responses[] = $response_nb;
    $responses_strings[] = $response_string;
}

//normalize the values
$coef = $height / max($responses);

$normalized_responses = array();
while (list($key, $val) = each($responses))
    $normalized_responses[] = floor($val * $coef);

//set the bar width
$bar_width = floor($width / (count($responses) * 2));

//send the required header for a WBMP image
header ("Content-type: image/vnd.wap.wbmp");
 

$im = @ImageCreate ($width, $height + 10) or die ("Cannot Initialize new GD image stream");

$background_color = ImageColorAllocate ($im, 255, 255, 255);
$text_color = ImageColorAllocate ($im, 233, 14, 91);

for ($i=0, $pos=0; $i<count($responses); $i++, $pos+=2*$bar_width) {
    //draw a vertical bar
    if ($normalized_responses[$i] > 0) ImageFilledRectangle ($im, $pos+$bar_width, $height-$normalized_responses[$i], $pos+ 2*$bar_width, $height, 255);
    //draw vertical text
    ImageStringUp ($im, 1, $pos+2, $height,  $responses_strings[$i], $text_color);
}

//send the image to the browser
ImageWBMP ($im);

?>


Here is an example of screen that can be obtained:


 

Conclusion

This brief article shows how easy it is to create dynamic WML applications using PHP and MySQL. This small application could obviously be extended: it could display the total number of answers, allow written comments to be attached when voting, etc.

Olivier Elemento is a consultant in fixed and mobile Internet software technologies. You can contact him at elemento@club-internet.fr and have a look at its web page at http://genomenews.free.fr/cv.html