IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management  >

DB2 和开放源代码: 用 DB2、PHP 和 Linux 实现 Web 投票

投下您的一票

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 初级

Aron Lurie (aron@lurie.biz), 七年级毕业生, Middle School/Hebrew College
Marty Lurie (lurie@us.ibm.com), 系统工程师, IBM

2004 年 10 月 01 日

Web 投票或 Web 表决为从网站访问者那里获得反馈提供了一种很好的方式。本文展示了如何使用 IBM® DB2® Universal Database™(UDB)、Hypertext Preprocessor (PHP) 和 Linux™ 将这项功能添加到 Web 站点中。您将研究的设计包括:使用数据库存储选票信息,使用 PHP 脚本语言实现投票,以及创建、管理和审查选票。

为什么要进行 Web 投票?

从访问者那里取得反馈

Web 投票或 Web 表决为从网站访问者那里获得反馈提供了一种很好的方式。本文将解释如何将这项功能添加到 Web 站点中。首先,您将看到关于如何进行有意义投票的设计方面的某些细节,之后再进入技术细节。您将研究的设计包括:使用数据库存储选票信息,使用 PHP 脚本语言实现投票,以及创建、管理和审查选票。将这项功能添加到 Web 站点非常简单。请注意,这里给出的代码是由一个 12 岁的孩子创建的。

示例投票

如果使用过 Web 浏览器,那么您可能已经见过 Web 投票这种形式,甚至还自己投过票。图 1 中便是一个 Web 投票的例子。在下一节中,您将研究该选票可能有质量问题的地方。这种选票会有“引导选民”的嫌疑。


图 1. 一种示例选票
示例投票

有很多方式可以实现 Web 投票,可以通过一个数据库来实现,或者只需发送 e-mail 给投票管理员就可以实现。投票活动越是活跃,数据库也就变得越是重要,通过数据库技术可以管理事务工作负载、投票结果以及产生报告。

小慌、谎言、统计及选票

统计常常受到责难,但它的确能提供对投票数据的深刻洞察。您所进行的投票有多大的有效性呢?这取决于问题和应答的措辞,还有您想从投票中得到什么样的结论。有些时候荒谬的投票错误也会成为报纸的头条。

由于这是一篇关于计算机的文章,而不是关于统计学的文章,因此本文只是一个缩减版的投票统计实验设计。请遵从下面的一组指导方针,尽量获得对网站访问者想法的理解。如果您试图使用投票来达到个人的目的,那么可能与这里的建议背道而驰了。图 1 中的选票只是选票问答设计的一个模仿品。

  • 提供不包含判定性形容词的中立问题。
  • 提供包含多种选择的答案范围。
  • 包括一个“以上都不是”的选项,或投票者自己填写非指定的答案。
  • 尽量取得目标群体的随机抽样。
  • 即使有大量的人参与了投票,也不要假定得到的结果是有效的。
  • 即使只有少数人参与了投票,也不要假定得到的结果是无效的。
  • 记住,投票活动只是对以下人的抽样:
    • 来网站的人。
    • 选择在投票活动中投出选票的人。

在大多数情况下,大量的抽样可以提供可靠的结果。如果抽样较小,只要目标人口数不大,投票可能仍然是有效的。例如,如果您要对 1904 年 1 月 1 日出生的所有双胞胎进行一次投票,由于目前存活的目标人口规模已经很小,因此,如果参与投票的人很少,那么他可能代表存活的目标人口的 50% 甚至 100%。

即使有很多人响应,也未必能得到有效的结果。如果投票活动是政治性或宗教性的,那么网站可能会陷入问题双方激进组织的较量当中。这样一来,由于无法获得随机的抽样,投票只能反映各激进组织的组织技巧和精力。





回页首


投票系统的架构

图 2 中说明了浏览器、Web 服务器和数据库服务器。在本文中,所有组件都运行在 Red Hat Enterprise Server v3 上。以下列出了用于 DB2 的受支持的 Linux 发行版:
http://www-306.ibm.com/software/data/db2/linux/validate

您也可以选择在 Win32 上实现 Web 投票。


图 2. 浏览器、Web 服务器和数据库简图
浏览器、Web 服务器和数据库简图




回页首


实现 Web 投票的步骤概述

1. 收集各组件

您将需要 Apache、PHP 和 DB2 for Linux。Web 投票也可以在其他平台上实现,但是这里不作论述。

2. 安装和配置各组件

存在着很多这方面的文档。但是,本文只是特别谈到本系统所特有的文档。

3. 安装和配置源代码

要做到这一点,需要下载源代码 zip 文件 pollsource.zip。然后,需要将这些文件解压到 Apache "DocumentRoot" 所对应的文件夹中。默认情况下,该文件夹位于 Red Hat Linux 系统上,DocumentRoot 是 /var/www/html/

4. 存储选票数据

创建表和关系来存储选票信息。然后使用 SQL insert 语句创建一个简单的选票。此后创建的选票维护 PHP 屏幕是添加和维护选票的主要方式,您无需编写很多的 SQL 便可以使网站运行。





回页首


组件

本项目的三个关键部分是 Apache Web Server、PHP 编程环境和 DB2 服务器。关于如何安装和配置这些组件的文档已经有很多,因此在本文中,您将重点关注安装本环境时所特有的一些方面。关于安装和配置参考的链接,将在后面讨论。

Apache Web Server

www.apache.org 上提供了 Apache。Linux 发行版可能包括一个 Apache 环境。您将需要 apache/bin/apxs二进制文件来构建 PHP 环境。如果系统中没有安装该二进制文件,那么可以从 rpm安装,或者从源代码构建 Apache。

PHP

www.PHP.net上提供了 PHP。linux 发行版可能已经包含 PHP 环境。不过,为了一起使用 DB2 和 PHP,必须重新编译 PHP,以包括 Open Database Connectivity (ODBC) 支持。您可以在以下链接中找到关于如何完成这些操作的说明:
http://www.ibm.com/developerworks/cn/db2/library/techarticles/scott/0614_scott.html

DB2 UDB

DB2 Quick Beginnings 说明了安装和配置的各个步骤。为了验证安装和 ODBC 连接,需要进入 sample/cli 目录 ,并使用 bldapp脚本构建 dbinfo 样本。在使 DB2 运行之后,便可以将 PHP 连接到数据库。





回页首


连接各组件

下面是一篇关于如何连接 Apache、PHP 和 DB2 的好文章:
http://www.ibm.com/developerworks/cn/dmdd/library/techarticles/scott/0614_scott.shtml

设置数据库以便使用它

出于安全方面的原因,不要以管理员的身份连接到数据库。而是要暂时以 db2inst1的身份登录。完成登录之后,请运行下面三个命令:

db2 => create database phpweb
db2 => connect to phpweb
db2 => grant dbadm on database to phpweb

现在,就可以退出 db2inst1了。





回页首


存储 poll 数据

您将把投票问题和结果放入到一个数据库中,比如 DB2 中。将重要信息归入一个数据库中。这样做是为了便于访问、更新、备份、历史访问和管理。为了存储与投票相关的信息,还需要一个数据库模式。下面是所使用的表:

-表名: polls
	"polls" 表中的列是:
	pollkey —— 票号,这是主键。 
		question —— 投票问题的文本,放在一个 varchar 字段中。
		pollstartdate —— 投票起始日期。
		pollenddate —— 指定的投票截止日期。
表名: pollresponses
			"pollresponses" 表中的列是:
			responsekey —— 作为应答的惟一标识符,是主键。
			pollkey —— 对 "polls" 表的引用,以便将应答指派给一个投票问题。 
			responsenum —— 用于排列对某一特定问题的应答的编号。
			responsetext —— 应答的文本。
			votes —— 同意此应答的票数。

要创建这些表,可以使用以下 SQL:


清单 1. 用来存储投票问题和应答的模式
CONNECT TO PHPWEB;
CREATE TABLE polls (
    pollkey int primary key,
    question varchar(500),
    pollstartdate date,
    pollenddate date
);
CREATE TABLE pollresponses (
    responsekey int primary key,
    pollkey int references polls,
    responsenum int,
    responsetext varchar(300),
    votes int
);
-- create an index on the pollresponse pollkey column
-- since most joins use this to join to the polls table
create index i_response  on pollresponses ( pollkey );
--Example of creating a new poll
INSERT INTO polls VALUES 
(1, 'What do you think of this perfect article?', '2004-05-30','2005-01-01');
--The number 1 is the number of the poll, which is the primary key
--The question 'What do you think of this perfect article?' 
-- is the question the poll will 
--be asking.
--The date '2004-05-30' is the date the poll started. 
--The date '2004-03-22 is the date designated for this poll to end. 
--All dates must be in the format 'YYYY-MM-DD'.
--Example of adding a response that can be chosen by the poll-ee.
INSERT INTO pollresponses VALUES (1, 1, 1, 'It''s absolutely amazing!', 0);
--The first 1 is the number of the response out of all the responses for 
-- all the polls. 
--This is the primary key.
--The second 1 is the number of the primary key of the poll 
-- that this will be a response to.
--The third 1 is the number to order the responses that will 
-- appear within the specific poll that the response belongs to.
--'It''s absolutely amazing' is the text of the response
--The 0 is the amount of votes the response has. This number 
--should ALWAYS start at zero, and will be changed by the PHP script.
--Adding another response:
INSERT INTO pollresponses VALUES (2,1,2, 'It''s good', 0);

现在您已经配置好了这些表,接下来可以通过在浏览器中显示用于投票的 Web 页面来检验整个系统。





回页首


用 PHP 连接到数据库

当 Web 浏览器请求 PHP 脚本时,运行在 Apache 服务器中的 PHP 模块便将这些脚本呈现为 HTML 形式。下面第一个简单的脚本将打开一个数据库连接,并向浏览器发送消息确认该连接。也可以从命令行用 php 命令来运行。

该环境的 userid 是 phpweb,而不是 dbadmroot user。有特权的帐户应该只在必要的时候才使用特权,一般生产环境下不要用。请不要用 phpweb1 作为生产环境的口令!


清单 2. 用于通过 PHP 打开数据库连接的示例脚本
<?php
        $dbname = "PHPWEB";
        $username = "phpweb";
        $password = "phpweb1";
 
        // odbc_pconnect returns 0 if the connection attempt fails
        // otherwise it returns a connection ID used by other ODBC functions
                echo ( "attempt connect.....\n " );
        $conn = odbc_pconnect ( $dbname, $username, $password );
 
        if ( $conn == 0 ) {
                echo ( "Connection to database failed." );
		//If connection failed, show what the error message was:
                $sqlerror = odbc_errormsg ( $conn );
                echo ( $sqlerror );
        }
                echo ( "connect ok" );
?>

在 Apache 服务器环境下运行该 PHP 程序时,将产生如下屏幕:


图 3. 测试连接屏幕
测试连接屏幕

如果这次测试能够正常运行,那么现在就可以安装和运行投票系统的 PHP 代码了。





回页首


PHP 投票工具

投票工具分为两部分,一是实际的投票脚本,一是维护工具。您将分别探索这两部分。

运行投票的代码在 zip 文件中。这个 zip 文件包括投票脚本和用于管理选票的工具。为了满足您的需要,您需要对这些脚本做一些更改。





回页首


投票脚本

“投票脚本”包括:
  • index.php 文件,该文件或者是将用户带到可以选择对哪一项选票进行投票的地方,或者将他们带到投票屏幕,只对惟一给出的选票进行投票。
  • choosevote.php 文件,该文件允许用户从一个列表中选择投哪一票。
  • vote.php 文件,该文件是图 4 中显示的投票屏幕。
  • pollresults.php 文件,该文件允许用户查看投票结果,却不允许他们真正投票。
  • processvote.php 文件,该文件通过更新数据库来处理用户的投票,然后显示结果。
运行投票屏幕(vote.php)所得到的输出如下:
图 4. 示例投票屏幕
示例投票屏幕

按下投票按钮时,处理过程进入到 processvote.php 脚本。这将更新数据库表。

如何将新选票添加到 Web 站点呢?您不能期望使用投票系统的公众编写 SQL 语句来管理表中的问题和应答。

选票维护的一种较优雅的解决方案是提供管理 Web 投票的 Web 页面。现在,在下一节中研究如何在不离开 Web 浏览器的情况下进行选票维护。

维护脚本

“维护脚本”包括:

  • poll-create1.php、poll-create2.php 和 poll-create3.php 文件,这些文件是用来创建选票的工具。
  • poll-drop1.php 和 poll-drop2.php 文件,它们是用来删除选票的工具。
  • poll-manage1.php 文件,该文件是所有这些工具的“主页”。该页面提供了所有选票的一份详细列表,并插入了创建、删除和投票工具的链接。

选票管理包括创建和销毁选票。创建选票的工具有 3 个屏幕。图 5 中给出了选票创建工具的一个屏幕快照。

下面显示的维护屏幕大多数是无需解释的。这些屏幕的源代码在 zip 文件中。每个图的标签都包括 php 文件的名称。这样,在查看 zip 文件中的源代码时,就会更容易一些。


图 5. 主维护工具 —— poll-manage1.php
主维护工具

图 6. 第一个选票创建工具屏幕 —— poll-create1.php
第一个选票创建工具屏幕

图 7. 选票删除工具 —— poll-drop1.php
选票删除工具




回页首


投票背后的玄机

您已经看到了投票系统的两个不同的部分,也看过了实现这两个部分的文件,现在请看一看实现这些页面的源代码。同样,您将分别看到两个部分。

投票脚本

当用户来到 Web 站点时,他们碰到的第一个页面便是一个投票脚本,在这里是 index.php。index.php 将连接到数据库,并查看选票数据库中有多少未过期的条目。如果只有一个条目,那么该页面会将用户带到 vote.php 页面,让他们对这一项选票进行投票。否则,主页面会将用户带到 choosevote.php,让用户或者选择对多项选票中的哪一项进行投票,或者让他们知道当前没有选票。index.php 的源代码如清单 3 所示:


清单 3. index.php 的源代码
<?php
                                                                                
$dbname = "PHPWEB";
$username = "phpweb";
$password = "phpweb1";
                                                                                
$dbh = odbc_pconnect ( $dbname, $username, $password );
                                                                                
$today = date("Y-m-d");
$sql = "select * from polls where  pollenddate > '$today' order by pollkey";
$pollexec = odbc_exec($dbh , $sql);
$rows = odbc_num_rows($pollexec);
                                                                                
//if there is one current poll
if ($rows == "1")
{
   //sends the user to vote on that poll
   $data = odbc_fetch_object($pollexec);
   header("Location: vote.php?pollkey=$data->POLLKEY");
   exit;
}
//if there is more than one or zero current polls
else
{
   //sends the user to choosevote.php
   header("Location: choosevote.php");
   exit;
}
                                                                                
?>

如前所述,用户可以从 index.php转到两个地方,或者进入 vote.php页面,或者进入 choosevote.php页面。但是,如果因为有多项选票而导致用户进入了 choosevote.php,那么一旦他们单击某个链接,就会被带到 vote.php。如果用户进入 vote.php中,他们就可以进行投票,或者可以查看当前的结果。由于投票脚本更为有趣(也更复杂),所以我们将更详细地查看该脚本。这个名为 processvote.php 的脚本通过将投票添加到数据库中来处理用户的投票,并像 pollresults.php那样显示结果。processvote.php 的源代码(32 行)可以在下方的清单 4 中找到。


清单 4. processvote.php 的源代码
<?php
$dbname = "PHPWEB";
$username = "phpweb";
$password = "phpweb1";
$conn = odbc_pconnect ( $dbname, $username, $password );
//if the user doesn't choose an answer...
if($_POST[vote] == 0){
echo "You did not choose an answer.\n ";
die("<center><h2> Please go back and select one.");
}
$sqlstr= "select * from pollresponses where  responsekey = $_POST[vote]";
$getvotesnum = odbc_exec($conn, $sqlstr );
$votesnum = odbc_fetch_object($getvotesnum);
$today=date("Y-m-d");
$sqlstr= "select * from polls where pollkey=$votesnum->POLLKEY";
$getexpire=odbc_exec($conn, $sqlstr);
$expiredata=odbc_fetch_object($getexpire);
if ($expiredata->POLLENDDATE > "$today"){
$newvotesnum = $votesnum->VOTES+1;
$vote = odbc_exec($conn, "update pollresponses set 
        votes = $newvotesnum where responsekey = $_POST[vote]");
	$sql = "select * from pollresponses where pollkey = $_POST[pollkey] ";
	$sql .=	"order by responsekey";
$execute= odbc_exec($conn, $sql);
$rows = odbc_num_rows($execute);
echo "<center><h1>Poll Results</h1>";
echo "<h3>Question: $expiredata->QUESTION</h3>";
echo"<table name='table' border='0'>";
for ($i=1; $i<=$rows; $i++)
{
   //retrieve all the responses and their data, and display it
   $data = odbc_fetch_object($execute, $i);
   echo "<tr valign='center' rowspan='1' colspan='1' align='right'>";
   echo "<td valign = 'center' align = 'right' rowspan='1' colspan='1'>";
   echo "$data->RESPONSETEXT:</td><td>$data->VOTES votes";
   echo "</td></tr>";
}
echo "</table>";
echo "<br><a href='index.php'>Back To Poll Index</a>";
}
//if the poll has expired
else
{
echo "<center>Your vote was not processed because this poll has expired.";
echo "< br>To get to a list of polls that are not expired please click ";
echo "< a href='choosevote.php' class='primary'>here</a><br>";
echo "To view the results for this poll, please click ";
echo "<a href='pollresults.php?pollkey=$expiredata->POLLKEY'>here</a>.";
}
?>

您已经看过了投票脚本的一些源代码,现在可以转而查看维护脚本,您可以看到某个创建工具屏幕的源代码,以及主要维护工具的源代码。

维护脚本

选票维护是由管理员来执行的。执行维护的页面应该有口令保护。为了配置 Apache,以便对特定的目录使用口令,请查看 .htaccessAuthType 和命令 htpasswd 的文档。

维护脚本的结构并不是很复杂。其中有三个工具,每个工具平均有两页的代码。这一次,是由 Web 站点管理员、而不是用户来进行浏览。

与投票工具不同,现在这组工具没有 index.php 文件。不过,其中有个工具将充当主管理 Web 页面,其中有指向其他所有工具的链接。在本文中,您看不到该工具的源代码,不过可以看到其他两个工具 —— 创建和删除工具的源代码。

首先,看一下创建工具。创建工具有三个屏幕,但是这里您只能详细查看其中的第二个屏幕。第二个屏幕将来自第一个页面的所有信息都输入到数据库中,然后从用户那里收集更多的信息,这些信息将在第三个页面被输入到数据库中。清单 5 中显示了该页面,即 poll-create2.php 的源代码。


清单 5. poll-create2.php 的源代码
<?php
$dbname = "PHPWEB";
$username = "phpweb";
$password = "phpweb1";
$conn = odbc_pconnect ( $dbname, $username, $password );
//in this part of the script, it will add the question, startdate, 
// and enddate to the database
//the @ sign before the function tells the function not to 
// output any error messages or warnings
$pollkeyexec = @odbc_exec($conn, "select * from polls order by pollkey");
$rows2 = @odbc_num_rows($pollkeyexec);
$keydata2 = @odbc_fetch_object($pollkeyexec, $rows2);
$pollkey = $keydata2->POLLKEY+1;
//these replace functions change the \' created by the php parser into a '' 
//that the database can read, and changes the \" from php to a " for the 
//database
$str1 = str_replace ("\'", "''", $_POST[question]);
$str2 = str_replace ('\"', '"', $str1);
$today = @date("Y-m-d");
$insertpoll = odbc_exec($conn,"insert into polls values 
             ($pollkey, '$str2', '$today', '$_POST[enddate]')");
                 
//in this part, the script will collect more information from the admin
                                                               
echo "<center><h1>Create a Poll</h1></center>";
echo "<center>";
echo "<form name = 'newpoll' action = 'poll-create3.php' method='post'>";
echo "<table border = '0'>";
                                                                                
for ($i=0; $i<$_POST[numresponses];$i++){
$i2 = $i+1;
echo "<tr valign='center' rowspan='1' colspan='1' align='right'>";
echo "<td valign = 'center' align = 'right' rowspan='1' colspan='1'>";
echo "Response $i2:</td><td align='left'>";
echo "<input type = 'text' name = 'response$i2' size = '70'>";
echo "<br></td></tr>";
}
echo "</table>";
echo "<input type='hidden' value='$_POST[numresponses]' name='numresponses'>";
echo "<input type = 'submit' value= 'Next Step'>";
echo "</form>";
?>

现在,看一下删除工具。该工具将包含与要删除的选票相关的数据的所有行从 polls 和 pollresponses 表中删除。源代码显示在图 6 中,这段代码毋需解释,非常简短。


清单 6. poll-drop2.php 的源代码
<?php
echo "<center><h1>Delete A Poll</h1>";
echo "<br><h3>Poll $_POST[pollkey] has been deleted</h3>";
$dbname = "PHPWEB";
$username = "phpweb";
$password = "phpweb1";
$conn = odbc_pconnect ( $dbname, $username, $password );
$sqlstr = "delete from pollresponses where pollkey=$_POST[pollkey]";
$query = odbc_exec($conn, $sqlstr);
$query2 = odbc_exec($conn, "delete from polls where pollkey=$_POST[pollkey]");
echo "<hr width='50%'>";
echo "<a href='poll-manage1.php'>Back to Poll Admin Tool</a>";
?>





回页首


后续步骤

这里描述的环境是学习如何实现 PHP 和简单的 Web 投票系统的好起点。您可以根据自己站点的需要进行自定义。其他投票 PHP 代码和这里用到的技术,可以为理解投票的原理以及如何将数据存储在数据库中奠定良好的基础。

时时关注操作系统、httpd、php 和 DB2 维护,尤其是事关安全的方面,这一点很重要。订阅 Computer Emergency Readiness Team (CERT) 是实时了解安全问题的一个好方法,请访问 www.cert.org

当完成技术方面的工作之后,好的统计实验设计将成为从 Web 投票系统生成可靠结果的最重要的因素。






回页首


下载

名字大小下载方法
pollsource.zip7.32 KB
关于下载方法的信息


参考资料

要获得更多信息,请参阅:



作者简介

Author photo

在编写本文时,Aron 正要结束七年级的课程。之前,他已经有一家运营了两年的 Web 开发公司。Aron 为他的一个客户编写了本文中的 PHP 代码。他在 Hebrew 大学的高中部担任助理 Web 管理员。而且还是当地 USY 分会的 Web 管理员,他自愿腾出星期五下午的时间来为当地公立学校系统管理网站。虽然 Aron 的机器上运行着双引导系统,但他大部分时间还是扑在 Fedora Linux 上。他最大的一个愿望是有一个足够快的处理器,能够顺畅体验 Fedora Core 2。


Author photo

Marty Lurie 的计算机生涯始于纸带时期,那时他正在 IBM 1130 上尝试编写 Fortran 程序。平常他是 IBM 信息管理团队的一名 IT 专家,不过,如果您再多追问几句,他就会承认他主要在与计算机打交道。他最喜欢的程序是他自己编写的将其膝上型计算机连接到 Nordic Track 的程序(这台膝上型计算机的体重减轻了两磅,少了 20% 的“胆固醇”)。Marty 是 IBM 认证的 DB2 DBA、IBM 认证的商业智能解决方案专家(Business Intelligence Solutions Professional)以及 Informix 认证专家(Informix-certified Professional)。您可以通过 us.ibm.com 与他联系。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款