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的一个基础知识 表单提交
Jul 04 PHP
浅析PHP页面局部刷新功能的实现小结
Jun 21 PHP
php多种形式发送邮件(mail qmail邮件系统 phpmailer类)
Jan 22 PHP
PHP版微信公众平台红包API
Apr 02 PHP
PHP防止图片盗用(盗链)的方法小结
Nov 11 PHP
php实现的简单数据库操作Model类
Nov 16 PHP
PHP设置Cookie的HTTPONLY属性方法
Feb 09 PHP
PHP中overload与override的区别
Feb 13 PHP
ajax调用返回php接口返回json数据的方法(必看篇)
May 05 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
Jun 16 PHP
PHP获取ttf格式文件字体名的方法示例
Mar 06 PHP
记Laravel调用Gin接口调用formData上传文件的实现方法
Dec 12 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
PHP4之COOKIE支持详解
2006/10/09 PHP
用PHP制作静态网站的模板框架(二)
2006/10/09 PHP
PHP匿名函数和use子句用法实例
2016/03/16 PHP
PHP 范围解析操作符(::)用法分析【访问静态成员和类常量】
2020/04/14 PHP
MSN消息提示类
2006/09/05 Javascript
cookie丢失问题(认证失效) Authentication (用户验证信息)也会丢失
2009/06/04 Javascript
纯JavaScript实现的完美渐变弹出层效果代码
2010/04/02 Javascript
一个js的tab切换效果代码[代码分离]
2010/04/11 Javascript
nodejs获取本机内网和外网ip地址的实现代码
2014/06/01 NodeJs
JQuery悬停控制图片轮播——代码简单
2015/08/05 Javascript
JavaScript实现上下浮动的窗口效果代码
2015/10/12 Javascript
js实现仿购物车加减效果
2017/03/01 Javascript
angular中不同的组件间传值与通信的方法
2017/11/04 Javascript
AngularJs1.x自定义指令独立作用域的函数传入参数方法
2018/10/09 Javascript
react高阶组件添加和删除props
2019/04/26 Javascript
vue中使用百度脑图kityminder-core二次开发的实现
2019/09/26 Javascript
浅谈JSON5解决了JSON的两大痛点
2020/12/14 Javascript
Python类的用法实例浅析
2015/05/27 Python
Python解析json文件相关知识学习
2016/03/01 Python
深入理解Python中range和xrange的区别
2017/11/26 Python
python list元素为tuple时的排序方法
2018/04/18 Python
基于Python的PIL库学习详解
2019/05/10 Python
python中count函数简单的实例讲解
2020/02/06 Python
HTML5 video标签(播放器)学习笔记(一):使用入门
2015/04/24 HTML / CSS
南非最受欢迎的时尚品牌:MRP
2016/09/18 全球购物
Skyscanner新西兰:全球领先的旅游搜索网站
2019/08/26 全球购物
试述DBMS的主要功能
2016/11/13 面试题
自考自我鉴定范文
2013/10/30 职场文书
门前三包责任书
2014/04/15 职场文书
大学军训自我鉴定大全
2014/09/18 职场文书
工厂仓管员岗位职责
2015/04/01 职场文书
2016抗战胜利71周年红领巾广播稿
2015/12/18 职场文书
启迪人心的励志语录:脾气永远不要大于本事
2020/01/02 职场文书
解析在浏览器地址栏输入一个URL后发生了什么
2021/06/21 Servers
聊聊基于pytorch实现Resnet对本地数据集的训练问题
2022/03/25 Python
Python利用zhdate模块实现农历日期处理
2022/03/31 Python