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 相关文章推荐
Discuz板块横排显示图片的实现方法
May 28 PHP
php Ajax乱码
Apr 09 PHP
PHP 巧用数组降低程序的时间复杂度
Jan 01 PHP
php的一些小问题
Jul 03 PHP
基于MySQL到MongoDB简易对照表的详解
Jun 03 PHP
PHP中spl_autoload_register函数的用法总结
Nov 07 PHP
destoon二次开发模板及调用语法汇总
Jun 21 PHP
php通过隐藏表单控件获取到前两个页面的url
Sep 09 PHP
PHP进程同步代码实例
Feb 12 PHP
必须收藏的php实用代码片段
Feb 02 PHP
php的api数据接口书写实例(推荐)
Sep 22 PHP
PHP实现八皇后算法
May 06 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多文件上传功能实现原理及代码
2013/04/18 PHP
PHP删除目录及目录下所有文件的方法详解
2013/06/06 PHP
PHP代码判断设备是手机还是平板电脑(两种方法)
2015/10/19 PHP
开启PHP的伪静态模式
2015/12/31 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
2016/05/23 PHP
thinkPHP5.0框架API优化后的友好性分析
2017/03/17 PHP
Js 弹出框口并返回值的两种常用方法
2010/12/30 Javascript
简易js代码实现计算器操作
2013/04/15 Javascript
设置jsf的选择框h:selectOneMenu为不可编辑状态的方法
2014/01/07 Javascript
Javascript基础知识(三)BOM,DOM总结
2014/09/29 Javascript
javascript Deferred和递归次数限制实例
2014/10/21 Javascript
javascript解决IE6下hover问题的方法
2015/07/28 Javascript
基于jQuery实现以手风琴方式展开和折叠导航菜单
2016/01/28 Javascript
使用ES6语法重构React代码详解
2017/05/09 Javascript
JS手机端touch事件计算滑动距离的方法示例
2017/10/26 Javascript
理解Koa2中的async&amp;await的用法
2018/02/05 Javascript
jQuery zTree插件使用简单教程
2019/08/16 jQuery
JS图片懒加载技术实现过程解析
2020/07/27 Javascript
python中sets模块的用法实例
2014/09/30 Python
Python处理字符串之isspace()方法的使用
2015/05/19 Python
在python中对变量判断是否为None的三种方法总结
2019/01/23 Python
python Dijkstra算法实现最短路径问题的方法
2019/09/19 Python
使用python写一个自动浏览文章的脚本实例
2019/12/05 Python
Python常用库大全及简要说明
2020/01/17 Python
英国复古和经典球衣网站:Vintage Football Shirts
2018/10/05 全球购物
static函数与普通函数有什么区别
2015/12/25 面试题
保险公司年会主持词
2014/03/22 职场文书
美术第二课堂活动总结
2014/07/08 职场文书
公司副总经理岗位职责
2014/10/01 职场文书
2014年初一班主任工作总结
2014/11/08 职场文书
《倍数和因数》教学反思
2016/02/23 职场文书
2019通用版劳动合同范本!
2019/07/11 职场文书
MySQL中in和exists区别详解
2021/06/03 MySQL
SpringBoot+Redis实现布隆过滤器的示例代码
2022/03/17 Java/Android
Python中 range | np.arange | np.linspace三者的区别
2022/03/22 Python
win10重装系统后上不了网怎么办 win10重装系统网络故障的解决办法
2022/07/23 数码科技