PHP+MySQL投票系统的设计和实现分享
发布时间:2020-12-13 06:10:32 所属栏目:PHP教程 来源:网络整理
导读:系统不大,完成这个系统的过程我分了三个步骤 数据库设计 系统框架设计 前端美化 数据库的设计 设计三张表:投票结果统计表(count_voting),投票人记录表(ip_votes),用户表(user) 投票结果统计表用于统计最后的投票记录,我给它弄了4个字段:被投票项
系统不大,完成这个系统的过程我分了三个步骤 数据库的设计设计三张表:投票结果统计表(count_voting),投票人记录表(ip_votes),用户表(user) 投票结果统计表用于统计最后的投票记录,我给它弄了4个字段:被投票项的名称(SelectName),被投票项标签名(LabelName)(起到分类的作用),票数(CountVotes)。 投票人记录表用于登记投票人的ip(IP),地理位置(Location),投票时间(VoteTime),被投票项名称(SelectName)。然后我还给它加一个ID。 用户表主要用于给管理员用的,包含用户名(name)和密码(passwd)。 生成表的sql脚本如下: <div class="codetitle"><a style="CURSOR: pointer" data="83520" class="copybut" id="copybut83520" onclick="doCopy('code83520')"> 代码如下:<div class="codebody" id="code83520"> -- -- 表的结构 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操作数据库,我它简单的封装一下: <div class="codetitle"><a style="CURSOR: pointer" data="75234" class="copybut" id="copybut75234" onclick="doCopy('code75234')"> 代码如下:<div class="codebody" id="code75234"> / 操作数据库 封装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(" 数据库连接失败(creater PDO Error!): ".$e->getMessage()." "); } } public function __destruct() { $this->pdo = null; } public function exec($sql) { } public function query($sql) { } } 把连接数据库的信息封装进去方便后续的操作。 <div class="codetitle"><a style="CURSOR: pointer" data="53207" class="copybut" id="copybut53207" onclick="doCopy('code53207')"> 代码如下:<div class="codebody" id="code53207"> <?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." "; // 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); } } ?> 下面还有需要的函数 <div class="codetitle"><a style="CURSOR: pointer" data="92728" class="copybut" id="copybut92728" onclick="doCopy('code92728')"> 代码如下:<div class="codebody" id="code92728"> <?php /* 页面跳转函数 使用js实现 @param string $url / function goToPgae($url) { echo ""; } function jsFunc($fun,$arg=null) { echo ""; } function jsFunc3($fun,$arg1=null,$arg2=null,$arg3=null) { echo ""; //echo $fun."('$arg1','$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,$mb); $str = strip_tags($mb[0][1]); $str = str_replace(' ',$str); $address = substr($str,7); if($address == '') { $address = '未明'; } return $address; } ?> 然后就是后台管理员的操作怎么弄了,主要是添加投票项的功能,操作数据库上面已经实现。后面的基本上是页面怎么设置,关系到js。添加投票项的页面是动态的,如下: <div class="codetitle"><a style="CURSOR: pointer" data="74166" class="copybut" id="copybut74166" onclick="doCopy('code74166')"> 代码如下:<div class="codebody" id="code74166"> function addVote() { right.innerHTML=" 添加投票项";right.innerHTML+=" |