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简单命令代码集锦
Sep 24 PHP
使用bcompiler对PHP文件进行加密的代码
Aug 29 PHP
php中批量删除Mysql中相同前缀的数据表的代码
Jul 01 PHP
php获取网卡的MAC地址支持WIN/LINUX系统
Apr 30 PHP
PHP实现视频文件上传完整实例
Aug 28 PHP
php自定义时间转换函数示例
Dec 07 PHP
关于php支持的协议与封装协议总结(推荐)
Nov 17 PHP
PHP使用zlib扩展实现GZIP压缩输出的方法详解
Apr 09 PHP
PHP中常见的密码处理方式和建议总结
Oct 14 PHP
PHP addAttribute()函数讲解
Feb 03 PHP
[原创]PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】
Jul 12 PHP
关于laravel 数据库迁移中integer类型是无法指定长度的问题
Oct 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重定向的三种方法分享
2012/02/22 PHP
php获取网页中图片、DIV内容的简单方法
2014/06/19 PHP
javascript对象之内置对象Math使用方法
2010/04/16 Javascript
js获取浏览器的可视区域尺寸的实现代码
2011/11/30 Javascript
javascript面向对象包装类Class封装类库剖析
2013/01/24 Javascript
jquery实现的一个导航滚动效果具体代码
2013/05/27 Javascript
js中实现多态采用和继承类似的方法
2014/08/22 Javascript
javascript实现切换td中的值
2014/12/05 Javascript
Javascript中arguments和arguments.callee的区别浅析
2015/04/24 Javascript
jQuery实现冻结表格行和列
2015/04/29 Javascript
JavaScript检测鼠标移动方向的方法
2015/05/22 Javascript
基于jQuery实现自动轮播旋转木马特效
2015/11/02 Javascript
javascript匀速动画和缓冲动画详解
2016/10/20 Javascript
js实现导航吸顶效果
2017/02/24 Javascript
Angular2里获取(input file)上传文件的内容的方法
2017/09/05 Javascript
JavaScript定义及输出螺旋矩阵的方法详解
2017/12/01 Javascript
在vue里面设置全局变量或数据的方法
2018/03/09 Javascript
30分钟快速入门掌握ES6/ES2015的核心内容(上)
2018/04/18 Javascript
vue 标签属性数据绑定和拼接的实现方法
2018/05/17 Javascript
vue-axios同时请求多个接口 等所有接口全部加载完成再处理操作
2020/11/09 Javascript
Python判断Abundant Number的方法
2015/06/15 Python
Python实现两款计算器功能示例
2017/12/19 Python
Python paramiko模块的使用示例
2018/04/11 Python
pandas数据处理基础之筛选指定行或者指定列的数据
2018/05/03 Python
python实现五子棋游戏
2019/06/18 Python
python多线程http压力测试脚本
2019/06/25 Python
python3.7 使用pymssql往sqlserver插入数据的方法
2019/07/08 Python
什么是python的必选参数
2020/06/21 Python
详解pycharm自动import所需的库的操作方法
2020/11/30 Python
HTML5 3D旋转相册的实现示例
2019/12/03 HTML / CSS
四查四看剖析材料
2014/02/14 职场文书
乡镇党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
公司出纳岗位职责
2015/03/31 职场文书
浅谈Vue的computed计算属性
2022/03/21 Vue.js
vue3种table表格选项个数的控制方法
2022/04/14 Vue.js
Java 多线程协作作业之信号同步
2022/05/11 Java/Android