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


Posted in PHP onSeptember 23, 2012

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

数据库的设计
设计三张表:投票结果统计表(count_voting),投票人记录表(ip_votes),用户表(user)
投票结果统计表用于统计最后的投票记录,我给它弄了4个字段:被投票项的名称(SelectName),被投票项标签名(LabelName)(起到分类的作用),票数(CountVotes)。

投票人记录表用于登记投票人的ip(IP),地理位置(Location),投票时间(VoteTime),被投票项名称(SelectName)。然后我还给它加一个ID。

用户表主要用于给管理员用的,包含用户名(name)和密码(passwd)。

生成表的sql脚本如下:

-- 
-- 表的结构 `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, 
`CountVotes` bigint(20) unsigned NOT NULL, 
UNIQUE KEY `SelectName` (`SelectName`), 
KEY `CountVotes` (`CountVotes`), 
KEY `CountVotes_2` (`CountVotes`), 
KEY `CountVotes_3` (`CountVotes`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='投票统计表'; 
-- -------------------------------------------------------- 
-- 
-- 表的结构 `ip_votes` 
-- 
DROP TABLE IF EXISTS `ip_votes`; 
CREATE TABLE IF NOT EXISTS `ip_votes` ( 
`ID` bigint(20) unsigned NOT NULL auto_increment COMMENT '投票人序号:自增', 
`IP` varchar(15) NOT NULL COMMENT '投票人IP', 
`Location` varchar(40) NOT NULL COMMENT '投票人位置', 
`VoteTime` datetime NOT NULL, 
`SelectName` varchar(40) NOT NULL, 
PRIMARY KEY (`ID`), 
KEY `ID` (`ID`), 
KEY `SelectName` (`SelectName`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; 
-- 
-- 触发器 `ip_votes` 
-- 
DROP TRIGGER IF EXISTS `vote_count_after_insert_tr`; 
DELIMITER // 
CREATE TRIGGER `vote_count_after_insert_tr` AFTER INSERT ON `ip_votes` 
FOR EACH ROW UPDATE count_voting SET CountVotes = CountVotes + 1 WHERE SelectName = NEW.SelectName 
// 
DELIMITER ; 
-- -------------------------------------------------------- 
-- 
-- 表的结构 `user` 
-- 
DROP TABLE IF EXISTS `user`; 
CREATE TABLE IF NOT EXISTS `user` ( 
`name` varchar(10) NOT NULL COMMENT '管理员用户名', 
`passwd` char(32) NOT NULL COMMENT '登录密码MD5值' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表'; 
-- 
-- 转存表中的数据 `user` 
-- 
INSERT INTO `user` (`name`, `passwd`) VALUES 
('ttxi', '700469ca1555900b18c641bf7b0a1fa1'), 
('jitttanwa', 'adac5659956d68bcbc6f40aa5cd00d5c'); 
-- 
-- 限制导出的表 
-- 
-- 
-- 限制表 `ip_votes` 
-- 
ALTER TABLE `ip_votes` 
ADD CONSTRAINT `ip_votes_ibfk_1` FOREIGN KEY (`SelectName`) REFERENCES `count_voting` (`SelectName`) ON DELETE CASCADE ON UPDATE CASCADE;

从脚本中可以看出,我创建了一个触发器,当往ip_votes表中插入数据的时候就给count_voting表中的CountVotes字段加1。还能后出最后一句是设置外部关联字。
框架设计
OperatorDB类用于操作数据库,OperatorVotingDB类用于该系统特定的操作集合。
使用PDO操作数据库,我它简单的封装一下:
/** 
* 操作数据库 
* 封装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("php_pdo_mysql.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("<br/>数据库连接失败(creater PDO Error!): ".$e->getMessage()."<br/>"); 
} 
} 
public function __destruct() 
{ 
$this->pdo = null; 
} 
public function exec($sql) 
{ 
} 
public function query($sql) 
{ 
} 
}

把连接数据库的信息封装进去方便后续的操作。
<?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."<br>"; 
// 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); 
} 
} 
?>

下面还有需要的函数
<?php 
/** 
* 页面跳转函数 
* 使用js实现 
* @param string $url 
*/ 
function goToPgae($url) 
{ 
echo "<script language='javascript' type='text/javascript'>"; 
echo "window.location.href='$url'"; 
echo "</script>"; 
} 
function jsFunc($fun, $arg=null) 
{ 
echo "<script language='javascript' type='text/javascript'>"; 
echo $fun."('$arg');"; 
echo "</script>"; 
} 
function jsFunc3($fun, $arg1=null,$arg2=null,$arg3=null) 
{ 
echo "<script language='javascript' type='text/javascript'>"; 
echo $fun."('$arg1','$arg2','$arg3');"; 
echo "</script>"; 
//echo $fun."('$arg1','$arg2','$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, $content, $mb); 
$str = strip_tags($mb[0][1]); 
$str = str_replace(' ', '', $str); 
$address = substr($str, 7); 
if($address == '') { 
$address = '未明'; 
} 
return $address; 
} 
?>

然后就是后台管理员的操作怎么弄了,主要是添加投票项的功能,操作数据库上面已经实现。后面的基本上是页面怎么设置,关系到js。添加投票项的页面是动态的,如下:
function addVote() 
{ 
right.innerHTML="<h2>添加投票项</h2>"; 
right.innerHTML+="<label>投票项标签<label>"; 
addInput("right","cLabelName","地区名"); 
right.innerHTML+="<br><label>投票项名称<label>"; 
addInput("right","cSelectName","学校名"); 
right.innerHTML+="<br>"; 
var args = '\'./add.php\',\'cSelectName\',\'cLabelName\''; 
var str = '<input type=button value="\u6dfb加" onclick="goToPage('+args+');"/>'; 
right.innerHTML+=str; 
} 
//添加文本框 
function addInput(parent,id,pla) 
{ 
//创建input 
var input = document.createElement("input"); 
input.type = "text"; 
input.id = id; 
input.placeholder = pla; 
document.getElementById(parent).appendChild(input); 
}

效果:

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

清空投票项也差不多,下过如下:

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

添加投票项是通过url传递变量到add.php页面的。
<?php 
require_once '../api/func.php'; if (!isLoginNow()) 
{ 
goToPgae("./index.php"); 
} 
$name = $_GET["cSelectName"]; 
$label = $_GET["cLabelName"]; 
//echo $name."<br>".$label; 
require_once '../api/OperatorVotingDB.php'; 
$ovdb=new OperatorVotingDB(); 
$ovdb->addSelectName($name,$label); 
require './header.htm'; 
goToPgae("./admin.php?page=add&auto="."$label"."&id=cLabelName&foc=cSelectName&msg=添加成功"); 
?>

下面是两个跳转页面的函数,js的(上面func.php中的跳转页面函数也是通过js实现的)。
//js 
function goToPage(url,arg1,arg2) 
{ 
var a = document.getElementById(arg1).value; 
var b = document.getElementById(arg2).value; 
url += '?'+arg1+'='+a; 
url += '&'+arg2+'='+b; 
window.location.href=url; 
} function goToPage1(url) 
{ 
window.location.href=url; 
}

还有修改删除功能没有实现。我应该不会去实现那个了吧,js的话和添加功能差不多。

登录模块的话网上很多,模仿的。就是提交表单,查找数据库,返回结果。成功则设置cookie,后台的每个页面都添加了检测cookie的功能的。

前端美化
index.php页面首先操作数据库获取投票项和票数,然后显示出来(通过css+div美化一下框架界面什么的),最后点击投票按钮就提交表单,跳转到vote.php页面。

css的话我都是抄网上的。我弄的效果如下:

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

这个东西算是个很小的信息管理系统吧,我已经把这个东西的源代码放到github(https://github.com/hanxi/voting)上去了,可以随意下载修改也可以到三水点靠木下载(点击下载)。欢迎读者回复交流,这方面不是我的强项,有很多不足之处还望指教。

作者:涵曦(涵曦的技术博客 - 博客园)
微博:t.qq.com/hanxi1203
出处:hanxi.cnblogs.com

PHP 相关文章推荐
php 随机生成10位字符代码
Mar 26 PHP
关于php curl获取301或302转向的网址问题的解决方法
Jun 02 PHP
深入理解PHP之数组(遍历顺序)  Laruence原创
Jun 13 PHP
php旋转图片90度的方法
Nov 07 PHP
PHP通过串口实现发送短信
Jul 08 PHP
PHP中COOKIES使用示例
Jul 26 PHP
php检查字符串中是否有外链的方法
Jul 29 PHP
PHP大文件分割上传 PHP分片上传
Aug 28 PHP
PHP操作路由器实现方法示例
Apr 27 PHP
php实现微信公众号创建自定义菜单功能的实例代码
Jun 11 PHP
tp5.1 框架join方法用法实例分析
May 26 PHP
详解Go与PHP的语法对比
May 29 PHP
详解php的魔术方法__get()和__set()使用介绍
Sep 19 #PHP
php引用计数器进行垃圾收集机制介绍
Sep 19 #PHP
mysql,mysqli,PDO的各自不同介绍
Sep 19 #PHP
php数组相加 array(“a”)+array(“b”)结果还是array(“a”)
Sep 19 #PHP
PHP输入流php://input介绍
Sep 18 #PHP
PHP爆绝对路径方法收集整理
Sep 17 #PHP
php中inlcude()性能对比详解
Sep 16 #PHP
You might like
php缓冲 output_buffering和ob_start使用介绍
2014/01/30 PHP
ThinkPHP控制器里javascript代码不能执行的解决方法
2014/11/22 PHP
php中Ctype函数用法详解
2014/12/09 PHP
php微信公众号开发之秒杀
2018/10/20 PHP
PHP函数积累总结
2019/03/19 PHP
用javascript实现改变TEXTAREA滚动条和按钮的颜色,以及怎样让滚动条变得扁平
2007/04/20 Javascript
jquery中eq和get的区别与使用方法
2011/04/14 Javascript
JS清除IE浏览器缓存的方法
2013/07/26 Javascript
JavaScript实现找质数代码分享
2015/03/24 Javascript
php+ajax+jquery实现点击加载更多内容
2015/05/03 Javascript
jQuery实现的简单折叠菜单(折叠面板)效果代码
2015/09/16 Javascript
JavaScript实现阿拉伯数字和中文数字互相转换
2016/06/12 Javascript
jQuery实现扑克正反面翻牌效果
2017/03/10 Javascript
解决AngualrJS页面刷新导致异常显示问题
2017/04/20 Javascript
Vue写一个简单的倒计时按钮功能
2018/04/20 Javascript
JS实现的缓冲运动效果示例
2018/04/30 Javascript
30分钟快速实现小程序语音识别功能
2018/11/27 Javascript
小程序实现自定义导航栏适配完美版
2019/04/02 Javascript
在Django框架中运行Python应用全攻略
2015/07/17 Python
python实现爬虫统计学校BBS男女比例(一)
2015/12/31 Python
详解Golang 与python中的字符串反转
2017/07/21 Python
Python3内置模块random随机方法小结
2019/07/13 Python
Python的bit_length函数来二进制的位数方法
2019/08/27 Python
Python使用正则实现计算字符串算式
2019/12/29 Python
Python grpc超时机制代码示例
2020/09/14 Python
法国最大的在线眼镜店:EasyLunettes
2019/08/26 全球购物
Trench London官方网站:高级风衣和意大利皮夹克
2020/07/11 全球购物
自动化专业本科毕业生求职信
2013/10/20 职场文书
自动化系在校本科生求职信
2013/10/23 职场文书
通信工程专业毕业生推荐信
2013/12/25 职场文书
带香烟到学校抽的检讨书
2014/09/25 职场文书
三人合伙协议书范本
2014/10/29 职场文书
刑事撤诉申请书
2015/05/18 职场文书
幽默口才训练经典句子(48句)
2019/08/19 职场文书
css 边框添加四个角的实现代码
2021/10/16 HTML / CSS
JS实现九宫格拼图游戏
2022/06/28 Javascript