微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

PHP+MySQL投票系统的设计和实现分享

系统不大,完成这个系统的过程我分了三个步骤
数据库设计
•系统框架设计
•前端美化

数据库的设计


设计三张表:投票结果统计表(countvoting),投票人记录表(ipVotes),用户表(user)
投票结果统计表用于统计最后的投票记录,我给它弄了4个字段:被投票项的名称(SelectName),被投票项标签名(LabelName)(起到分类的作用),票数(CountVotes)。 投票人记录表用于登记投票人的ip(IP),地理位置(Location),投票时间(VoteTime),被投票项名称(SelectName)。然后我还给它加一个ID。 用户表主要用于给管理员用的,包含用户名(name)和密码(passwd)。 生成表的sql脚本如下:
<div class="codetitle"><a style="CURSOR: pointer" data="83520" class="copybut" id="copybut83520" onclick="doCopy('code83520')"> 代码如下:
<div class="codebody" id="code83520">
--
-- 表的结构 count_voting
--
DROP TABLE IF EXISTS count_voting;
CREATE TABLE IF NOT EXISTS count_voting (
SelectName varchar(40) NOT NULL,
LabelName varchar(40) NOT NULL,
Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s bigint(20) unsigned NOT NULL,
UNIQUE KEY SelectName (SelectName),
KEY Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s (Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s),
KEY Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s_2 (Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s),
KEY Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s_3 (Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='投票统计表';
-- --------------------------------------------------------
--
-- 表的结构 ip_<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s
--
DROP TABLE IF EXISTS ip_<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s;
CREATE TABLE IF NOT EXISTS ip_<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s (
ID bigint(20) unsigned NOT NULL auto_increment COMMENT '投票人序号:自增',
IP varchar(15) NOT NULL COMMENT '投票人IP',
Location varchar(40) NOT NULL COMMENT '投票人位置',
<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>Time datetime NOT NULL,
SelectName varchar(40) NOT NULL,
PRIMARY KEY (ID),
KEY ID (ID),
KEY SelectName (SelectName)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTOINCREMENT=4 ;
--
-- 触发器 `ip
Votes<BR>-- <BR>DROP TRIGGER IF EXISTSVote_count_after_insert_tr; <BR>DELIMITER // <BR>CREATE TRIGGERVote_count_after_inserttrAFTER INSERT ONipVotes<BR>FOR EACH ROW UPDATE count_voting SET Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s = Count<a href="https://www.jb51.cc/tag/Vote/" target="_blank" class="keywords">Vote</a>s + 1 WHERE SelectName = NEW.SelectName <BR>// <BR>DELIMITER ; <BR>-- -------------------------------------------------------- <BR>-- <BR>-- 表的结构user<BR>-- <BR>DROP TABLE IF EXISTSuser; <BR>CREATE TABLE IF NOT EXISTSuser( <BR>namevarchar(10) NOT NULL COMMENT '<a href="https://www.jb51.cc/tag/guanliyuan/" target="_blank" class="keywords">管理员</a><a href="https://www.jb51.cc/tag/yonghuming/" target="_blank" class="keywords">用户名</a>',<BR>passwdchar(32) NOT NULL COMMENT '<a href="https://www.jb51.cc/tag/denglu/" target="_blank" class="keywords">登录</a>密码MD5值' <BR>) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='<a href="https://www.jb51.cc/tag/yonghu/" target="_blank" class="keywords">用户</a>表'; <BR>-- <BR>-- 转存表中的数据user<BR>-- <BR>INSERT INTOuser(name,passwd) VALUES <BR>('ttxi','700469ca1555900b18c641bf7b0a1fa1'),<BR>('jitttanwa','adac5659956d68bcbc6f40aa5cd00d5c'); <BR>-- <BR>-- 限制导出的表 <BR>-- <BR>-- <BR>-- 限制表ip_Votes<BR>-- <BR>ALTER TABLEip_Votes<BR>ADD CONSTRAINTip_Votes_ibfk_1FOREIGN KEY (SelectName) REFERENCEScount_voting(SelectName`) ON DELETE CASCADE ON UPDATE CASCADE;

从脚本中可以看出,我创建了一个触发器,当往ip_Votes表中插入数据的时候就给count_voting表中的CountVotes字段加1。还能后出最后一句是设置外部关联字。
框架设计
OperatorDB类用于操作数据库,OperatorVotingDB类用于该系统特定的操作集合。
使用PDO操作数据库,我它简单的封装一下:
<div class="codetitle"><a style="CURSOR: pointer" data="75234" class="copybut" id="copybut75234" onclick="doCopy('code75234')"> 代码如下:
<div class="codebody" id="code75234">
/
操作数据库
封装PDO,使其方便自己的操作
*/
class OperatorDB
{
//连接数据库的基本信息
private $dbms='MysqL'; //数据库类型,对于开发者来说,使用不同的数据库,只要改这个.
private $host='localhost'; //数据库主机名
private $dbname='voting'; //使用的数据库
private $user='voting'; //数据库连接用户名
private $passwd='voting'; //对应的密码
private $pdo=null;
public function construct()
{
//dl("PHP_pdo.dll");
//dl("PHPpdoMysqL.dll");
$this->dsn="$this->dbms:host=$this->host;dbname=$this->dbname";
try
{
$this->conn=new PDO($this->dsn,$this->user,$this->passwd);//初始化一个PDO对象,就是创建了数据库连接对象$db
}
catch(PDOException $e)
{
die("
数据库连接失败(creater PDO Error!): ".$e->getMessage()."
");
}
}
public function __destruct()
{
$this->pdo = null;
}
public function exec($sql)
{
}
public function query($sql)
{
}
}

把连接数据库的信息封装进去方便后续的操作。
<div class="codetitle"><a style="CURSOR: pointer" data="53207" class="copybut" id="copybut53207" onclick="doCopy('code53207')"> 代码如下:
<div class="codebody" id="code53207">
<?PHP
require_once 'OperatorDB.PHP';
class OperatorVotingDB
{
private $odb;
public function
construct()
{
$this->odb = new OperatorDB();
}
public function __destruct()
{
$this->odb = null;
}
/
清空Voting数据中的所有表

调用数据库操作类,执行clear数据库的操作
/
public function clearTables()
{
$sqls = array("TruncATE ip_Votes;","TruncATE count_voting;");
$this->odb->exec($sqls[0]);
$this->odb->exec($sqls[1]);
}
/

重置count_voting表中的CountValues字段为0

*/
public function resetCountValues()
{
$sql = "UPDATE count_voting SET CountVotes = 0;";
$this->odb->exec($sql);
}
/

投票
将信息写入ip_Votes表
@param type $ip
@param type $loc
@param type $time
@param type $name
*/
public function Vote($ip,$loc,$name)
{
$sql = "INSERT INTO ip_Votes VALUES (NULL,'$ip','$loc',Now(),'$name')";
$subsql = "SELECT MAX(to_days(VoteTime)) FROM ip_Votes WHERE IP='$ip'";
$stm = $this->odb->query($subsql);
if (count($row=$stm->fetchAll())==1)
{
$Now = date("Y-m-d H:i:s");
$subsql = "SELECT to_days('$Now');";
$stm = $this->odb->query($subsql)->fetch();
$time = $stm[0];//使用MysqL计算出的today时间
// echo $time."
";
// echo $row[0][0];
if ($time-$row[0][0]<1)//表中最大的时间和现在的时间$time比较
{
echo "投票失败,相同ip需要隔一天才能投票";
return;
}
}
// echo $sql;
echo "投票成功!";
$this->odb->exec($sql);
}
/
添加SelectName字段的行

@param string $name
@param string $label
@param int $count
/
public function addSelectName($name,$label,$count=0)
{
$sql = "INSERT INTO count_voting VALUES ('$name','$label',$count);";
$this->odb->exec($sql);
}
/

获取总投票情况,按票数排序的结果

按CountVotes字段排序,返回count_voting表

@param int $n

/
public function getVotesSortByCount($n=-1)
{
$sql = "SELECT
FROM count_voting ORDER BY CountVotes DESC LIMIT 0,$n;";
if (-1 == $n)
{
$sql = "SELECT * FROM count_voting ORDER BY CountVotes DESC;";
}
// echo $sql;
return $this->odb->query($sql);
}
/*
获取投票情况,按票数排序并按标签分组的结果

按CountVotes字段排序并按LabelName字段分组,返回count_voting表
/
public function getVotesGroupByLabel()
{
$sql = "SELECT
FROM count_voting ORDER BY LabelName DESC;";
// echo $sql;
return $this->odb->query($sql);
}
}
?>

下面还有需要的函数
<div class="codetitle"><a style="CURSOR: pointer" data="92728" class="copybut" id="copybut92728" onclick="doCopy('code92728')"> 代码如下:
<div class="codebody" id="code92728">
<?PHP
/*
页面跳转函数
使用js实现
@param string $url
/
function goToPgae($url)
{
echo "";
}
function jsFunc($fun,$arg=null)
{
echo "";
}
function jsFunc3($fun,$arg1=null,$arg2=null,$arg3=null)
{
echo "";
//echo $fun."('$arg1','$arg3');";
}
function isLoginNow()
{
if ($_COOKIE["user"]=='')
{
return false;
}
return true;
}
function getClientIP()
{
if ($_SERVER["HTTP_X_FORWARDED_FOR"])
{
if ($_SERVER["HTTP_CLIENT_IP"])
{
$proxy = $_SERVER["HTTP_CLIENT_IP"];
}
else
{
$proxy = $_SERVER["REMOTE_ADDR"];
}
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}
else
{
if ($_SERVER["HTTP_CLIENT_IP"])
{
$ip = $_SERVER["HTTP_CLIENT_IP"];
}
else
{
$ip = $_SERVER["REMOTE_ADDR"];
}
}
return $ip;
}
//从123查获取ip
function getIpfrom123cha($ip) {
$url = 'http://www.123cha.com/ip/?q='.$ip;
$content = file_get_contents($url);
$preg = '/(?<=本站主数据:<\/li><li style=\"width:450px;\">)(.
)(?=<\/li>)/isU';
preg_match_all($preg,$content,$mb);
$str = strip_tags($mb[0][0]);
//$str = str_replace(' ','',$str);
$address = $str;
if($address == '') {
$address = '未明';
}
return $address;
}
//从百度获取ip所在地
function getIpfromBaidu($ip) {
$url = 'http://www.baidu.com/s?wd='.$ip;
$content = file_get_contents($url);
$preg = '/(?<=<p class=\"op_ip_detail\">)(.*)(?=<\/p>)/isU';
preg_match_all($preg,$mb);
$str = strip_tags($mb[0][1]);
$str = str_replace(' ',$str);
$address = substr($str,7);
if($address == '') {
$address = '未明';
}
return $address;
}
?>

然后就是后台管理员的操作怎么弄了,主要是添加投票项的功能,操作数据库上面已经实现。后面的基本上是页面怎么设置,关系到js。添加投票项的页面是动态的,如下:
<div class="codetitle"><a style="CURSOR: pointer" data="74166" class="copybut" id="copybut74166" onclick="doCopy('code74166')"> 代码如下:<div class="codebody" id="code74166">
function addVote()
{
right.innerHTML="

添加投票项

";
right.innerHTML+="