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 相关文章推荐
手把手教你使用DedeCms的采集的图文教程
Mar 11 PHP
深入理解PHP几个算法:PHP冒泡、PHP二分法、PHP求素数、PHP乘法表
Jun 06 PHP
慎用preg_replace危险的/e修饰符(一句话后门常用)
Jun 19 PHP
PHP 解决session死锁的方法
Jun 20 PHP
ThinkPHP写数组插入与获取最新插入数据ID实例
Nov 03 PHP
PHP中创建和验证哈希的简单方法实探
Jul 06 PHP
WordPress中用于获取及自定义头像图片的PHP脚本详解
Dec 17 PHP
thinkphp框架下404页面设置 仅三步
May 14 PHP
php curl常用的5个经典例子
Jan 20 PHP
PHP实现上传图片到数据库并显示输出的方法
May 31 PHP
Laravel框架路由管理简单示例
May 07 PHP
PHP+Redis开发的书签案例实战详解
Jul 09 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使用get_headers函数判断远程文件是否存在的方法
2014/11/28 PHP
php判断文件上传类型及过滤不安全数据的方法
2014/12/17 PHP
可输入的下拉框
2006/06/19 Javascript
jquery与js函数冲突的两种解决方法
2013/09/09 Javascript
node.js中的fs.rmdir方法使用说明
2014/12/16 Javascript
JavaScript实现N皇后问题算法谜题解答
2014/12/29 Javascript
javascript实现带节日和农历的日历特效
2015/02/01 Javascript
浅析JavaScript 调试方法和技巧
2015/10/22 Javascript
深入理解node exports和module.exports区别
2016/06/01 Javascript
jquery横向纵向鼠标滚轮全屏切换
2017/02/27 Javascript
JavaSctit 利用FileReader和滤镜上传图片预览功能
2017/09/05 Javascript
JavaScript交换变量常用4种方法解析
2020/09/02 Javascript
[02:12]2015国际邀请赛 SHOWOPEN
2015/08/05 DOTA
[01:02:48]2018DOTA2亚洲邀请赛小组赛 A组加赛 Newbee vs Liquid
2018/04/03 DOTA
[53:52]OG vs EG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
pycharm中连接mysql数据库的步骤详解
2017/05/02 Python
Python引用类型和值类型的区别与使用解析
2017/10/17 Python
Scrapy抓取京东商品、豆瓣电影及代码分享
2017/11/23 Python
对Python发送带header的http请求方法详解
2019/01/02 Python
Python静态类型检查新工具之pyright 使用指南
2019/04/26 Python
对python3 sort sorted 函数的应用详解
2019/06/27 Python
python实时检测键盘输入函数的示例
2019/07/17 Python
详解基于python-django框架的支付宝支付案例
2019/09/23 Python
Python 基于FIR实现Hilbert滤波器求信号包络详解
2020/02/26 Python
使用Matplotlib绘制不同颜色的带箭头的线实例
2020/04/17 Python
纯CSS3实现表单验证效果(非常不错)
2017/01/18 HTML / CSS
Interrail法国:乘火车探索欧洲,最受欢迎的欧洲铁路通票
2019/08/27 全球购物
物流管理专业大学生自荐信
2013/10/04 职场文书
个人简历自荐信
2013/12/05 职场文书
王老吉广告词
2014/03/20 职场文书
员工生日活动方案
2014/08/24 职场文书
2014年机关工会工作总结
2014/12/19 职场文书
2014年度考核工作总结
2014/12/24 职场文书
教师工作表现评语
2014/12/31 职场文书
培训感想范文
2015/08/07 职场文书
Python实现简繁体转换
2021/06/07 Python