PHP+MySQL投票系统的设计和实现分享
程序员文章站
2023-12-04 08:00:51
系统不大,完成这个系统的过程我分了三个步骤 •数据库设计 •系统框架设计 •前端美化 数据库的设计 设计三张表:投票结果统计表(coun...
系统不大,完成这个系统的过程我分了三个步骤
•数据库设计
•系统框架设计
•前端美化
数据库的设计
设计三张表:投票结果统计表(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
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的话我都是抄网上的。我弄的效果如下:
这个东西算是个很小的信息管理系统吧,我已经把这个东西的源代码放到github()上去了,可以随意下载修改也可以到下载()。欢迎读者回复交流,这方面不是我的强项,有很多不足之处还望指教。
作者:涵曦(涵曦的技术博客 - 博客园)
微博:t.qq.com/hanxi1203
出处:hanxi.cnblogs.com
•数据库设计
•系统框架设计
•前端美化
数据库的设计
设计三张表:投票结果统计表(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);
}
效果:
清空投票项也差不多,下过如下:
添加投票项是通过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的话我都是抄网上的。我弄的效果如下:
这个东西算是个很小的信息管理系统吧,我已经把这个东西的源代码放到github()上去了,可以随意下载修改也可以到下载()。欢迎读者回复交流,这方面不是我的强项,有很多不足之处还望指教。
作者:涵曦(涵曦的技术博客 - 博客园)
微博:t.qq.com/hanxi1203
出处:hanxi.cnblogs.com