A-A+

php投票系统简单实现源码

2019年02月27日 我爱编程 暂无评论

数据库的设计:设计三张表,投票结果统计表(count_voting),投票人记录表(ip_votes),用户表(user).

投票结果统计表用于统计最后的投票记录,我给它弄了4个字段:被投票项的名称(SelectName),被投票项标签名(LabelName)(起到分类的作用),票数(CountVotes).

投票人记录表用于登记投票人的ip(IP),地理位置(Location),投票时间(VoteTime),被投票项名称(SelectName),然后我还给它加一个ID.

用户表主要用于给管理员用的,包含用户名(name)和密码(passwd).

生成表的sql脚本如下,代码如下:

  1. --
  2. -- 表的结构 `count_voting`
  3. --
  4. DROP TABLE IF EXISTS `count_voting`;
  5. CREATE TABLE IF NOT EXISTS `count_voting` (
  6.   `SelectName` varchar(40) NOT NULL,
  7.   `LabelName` varchar(40) NOT NULL,
  8.   `CountVotes` bigint(20) unsigned NOT NULL,
  9.   UNIQUE KEY `SelectName` (`SelectName`),
  10.   KEY `CountVotes` (`CountVotes`),
  11.   KEY `CountVotes_2` (`CountVotes`),
  12.   KEY `CountVotes_3` (`CountVotes`)
  13. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='投票统计表';
  14. -- --------------------------------------------------------
  15. --
  16. -- 表的结构 `ip_votes`
  17. --
  18. DROP TABLE IF EXISTS `ip_votes`;
  19. CREATE TABLE IF NOT EXISTS `ip_votes` (
  20.   `ID` bigint(20) unsigned NOT NULL auto_increment COMMENT '投票人序号:自增',
  21.   `IP` varchar(15) NOT NULL COMMENT '投票人IP',
  22.   `Location` varchar(40) NOT NULL COMMENT '投票人位置',
  23.   `VoteTime` datetime NOT NULL,
  24.   `SelectName` varchar(40) NOT NULL,
  25.   PRIMARY KEY  (`ID`),
  26.   KEY `ID` (`ID`),
  27.   KEY `SelectName` (`SelectName`)
  28. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
  29. --
  30. -- 触发器 `ip_votes`
  31. --
  32. DROP TRIGGER IF EXISTS `vote_count_after_insert_tr`;
  33. DELIMITER //
  34. CREATE TRIGGER `vote_count_after_insert_tr` AFTER INSERT ON `ip_votes`
  35.  FOR EACH ROW UPDATE count_voting SET CountVotes = CountVotes + 1 WHERE SelectName = NEW.SelectName
  36. //
  37. DELIMITER ;
  38. -- --------------------------------------------------------
  39. --
  40. -- 表的结构 `user`
  41. --
  42. DROP TABLE IF EXISTS `user`;
  43. CREATE TABLE IF NOT EXISTS `user` (
  44.   `namevarchar(10) NOT NULL COMMENT '管理员用户名',
  45.   `passwd` char(32) NOT NULL COMMENT '登录密码MD5值'
  46. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
  47. --
  48. -- 转存表中的数据 `user`
  49. --
  50. INSERT INTO `user` (`name`, `passwd`) VALUES
  51. ('ttxi''700469ca1555900b18c641bf7b0a1fa1'),
  52. ('jitttanwa''adac5659956d68bcbc6f40aa5cd00d5c');
  53. --
  54. -- 限制导出的表
  55. --
  56. --
  57. -- 限制表 `ip_votes`
  58. --
  59. ALTER TABLE `ip_votes`
  60.   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操作数据库,我它简单的封装一下,代码如下:

  1. /**
  2.  * 操作数据库
  3.  * 封装PDO,使其方便自己的操作
  4.  */
  5. class OperatorDB
  6. {
  7.     //连接数据库的基本信息
  8.     private $dbms='mysql';       //数据库类型,对于开发者来说,使用不同的数据库,只要改这个.
  9.     private $host='localhost';       //数据库主机名
  10.     private $dbName='voting';     //使用的数据库
  11.     private $user='voting';       //数据库连接用户名
  12.     private $passwd='voting';     //对应的密码
  13.     private $pdo=null;
  14.     public function  __construct()
  15.     {
  16.         //dl("php_pdo.dll");
  17.         //dl("php_pdo_mysql.dll");
  18.         $this->dsn="$this->dbms:host=$this->host;dbname=$this->dbName";
  19.         try
  20.         {
  21.             $this->conn=new PDO($this->dsn,$this->user,$this->passwd);//初始化一个PDO对象,就是创建了数据库连接对象$db
  22.         }
  23.         catch(PDOException $e)
  24.         {
  25.             die("<br/>数据库连接失败(creater PDO Error!): ".$e->getMessage()."<br/>");
  26.         }
  27.     }
  28.     public function __destruct()
  29.     {
  30.         $this->pdo = null;
  31.     }
  32.     public function exec($sql)
  33.     {
  34.     }
  35.     public function query($sql)
  36.     {
  37.     }
  38. }

把连接数据库的信息封装进去方便后续的操作,代码如下:

  1. <?php
  2. require_once 'OperatorDB.php';
  3. class OperatorVotingDB
  4. {
  5.     private $odb;
  6.     public function  __construct()
  7.     {
  8.         $this->odb = new OperatorDB();
  9.     }
  10.     public function __destruct()
  11.     {
  12.         $this->odb = null;
  13.     }
  14.     /**
  15.      * 清空Voting数据中的所有表
  16.      *
  17.      * 调用数据库操作类,执行clear数据库的操作
  18.      */
  19.     public function clearTables()
  20.     {
  21.         $sqls = array("TRUNCATE ip_votes;","TRUNCATE count_voting;");
  22.         $this->odb->exec($sqls[0]);
  23.         $this->odb->exec($sqls[1]);
  24.     }
  25.     /**
  26.      * 重置count_voting表中的CountValues字段为0
  27.      *
  28.      */
  29.     public function resetCountValues()
  30.     {
  31.         $sql = "UPDATE count_voting SET CountVotes = 0;";
  32.         $this->odb->exec($sql);
  33.     }
  34.     /**
  35.      * 投票
  36.      * 将信息写入ip_votes表
  37.      * @param type $ip
  38.      * @param type $loc
  39.      * @param type $time
  40.      * @param type $name
  41.      */
  42.     public function vote($ip,$loc,$name)
  43.     {
  44.         $sql = "INSERT INTO ip_votes VALUES (NULL, '$ip', '$loc', NOW(), '$name')";
  45.         $subsql = "SELECT MAX(to_days(VoteTime)) FROM ip_votes WHERE IP='$ip'";
  46.         $stm = $this->odb->query($subsql);
  47.         if (count($row=$stm->fetchAll())==1)
  48.         {
  49.             $now = date("Y-m-d H:i:s");
  50.             $subsql = "SELECT to_days('$now');";
  51.             $stm = $this->odb->query($subsql)->fetch();
  52.             $time = $stm[0];//使用mysql计算出的today时间
  53. //            echo $time."<br>";
  54. //            echo $row[0][0];
  55.             if ($time-$row[0][0]<1)//表中最大的时间和现在的时间$time比较
  56.             {
  57.                 echo "投票失败,相同ip需要隔一天才能投票";
  58.                 return;
  59.             }
  60.         }
  61. //        echo $sql;
  62.         echo "投票成功!";
  63.         $this->odb->exec($sql);
  64.     }
  65.     /**
  66.      * 添加SelectName字段的行
  67.      *
  68.      * @param string $name
  69.      * @param string $label
  70.      * @param int $count
  71.      */
  72.     public function addSelectName($name$label$count=0)
  73.     {
  74.         $sql = "INSERT INTO count_voting VALUES ('$name', '$label', $count);";
  75.         $this->odb->exec($sql);
  76.     }
  77.     /**
  78.      * 获取总投票情况,按票数排序的结果
  79.      *
  80.      * 按CountVotes字段排序,返回count_voting表
  81.      *
  82.      * @param int $n
  83.      *
  84.      */
  85.     public function getVotesSortByCount($n=-1)
  86.     {
  87.         $sql = "SELECT * FROM count_voting ORDER BY CountVotes DESC LIMIT 0 , $n;";
  88.         if (-1 == $n)
  89.         {
  90.             $sql = "SELECT * FROM count_voting ORDER BY CountVotes DESC;";
  91.         }
  92. //        echo $sql;
  93.         return $this->odb->query($sql);
  94.     }
  95.     /**
  96.      * 获取投票情况,按票数排序并按标签分组的结果
  97.      *
  98.      * 按CountVotes字段排序并按LabelName字段分组,返回count_voting表
  99.      */
  100.     public function getVotesGroupByLabel()
  101.     {
  102.         $sql = "SELECT * FROM count_voting ORDER BY LabelName DESC;";//开源代码phpfensi.com
  103. //        echo $sql;
  104.         return $this->odb->query($sql);
  105.     }
  106. }
  107. ?>

下面还有需要的函数,代码如下:

  1. <?php
  2. /**
  3.  * 页面跳转函数
  4.  * 使用js实现
  5.  * @param string $url
  6.  */
  7. function goToPgae($url)
  8. {
  9.     echo "<script language='javascript' type='text/javascript'>";
  10.     echo "window.location.href='$url'";
  11.     echo "</script>";
  12. }
  13. function jsFunc($fun$arg=null)
  14. {
  15.     echo "<script language='javascript' type='text/javascript'>";
  16.     echo $fun."('$arg');";
  17.     echo "</script>";
  18. }
  19. function jsFunc3($fun$arg1=null,$arg2=null,$arg3=null)
  20. {
  21.     echo "<script language='javascript' type='text/javascript'>";
  22.     echo $fun."('$arg1','$arg2','$arg3');";
  23.     echo "</script>";
  24.     //echo $fun."('$arg1','$arg2','$arg3');";
  25. }
  26. function isLoginNow()
  27. {
  28.     if ($_COOKIE["user"]=='')
  29.     {
  30.         return false;
  31.     }
  32.     return true;
  33. }
  34. function getClientIP()
  35. {
  36.     if ($_SERVER["HTTP_X_FORWARDED_FOR"])
  37.     {
  38.         if ($_SERVER["HTTP_CLIENT_IP"])
  39.         {
  40.                 $proxy = $_SERVER["HTTP_CLIENT_IP"];
  41.         }
  42.         else
  43.         {
  44.             $proxy = $_SERVER["REMOTE_ADDR"];
  45.         }
  46.         $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
  47.     }
  48.     else
  49.     {
  50.         if ($_SERVER["HTTP_CLIENT_IP"])
  51.         {
  52.                 $ip = $_SERVER["HTTP_CLIENT_IP"];
  53.         }
  54.         else
  55.         {
  56.             $ip = $_SERVER["REMOTE_ADDR"];
  57.         }
  58.     }
  59.     return $ip;
  60. }
  61. //从123查获取ip
  62. function getIpfrom123cha($ip) {
  63.     $url = 'http://www.123cha.com/ip/?q='.$ip;
  64.         $content = file_get_contents($url);
  65.         $preg = '/(?<=本站主数据:</li><li style="width:450px;">)(.*)(?=</li>)/isU';
  66.         preg_match_all($preg$content$mb);
  67.         $str = strip_tags($mb[0][0]);
  68.         //$str = str_replace(' ', '', $str);
  69.         $address = $str;
  70.         if($address == '') {
  71.             $address = '未明';
  72.         }
  73.     return $address;
  74. }
  75. //从百度获取ip所在地
  76. function getIpfromBaidu($ip) {
  77.     $url = 'http://www.baidu.com/s?wd='.$ip;
  78.     $content = file_get_contents($url);
  79.     $preg = '/(?<=<p class="op_ip_detail">)(.*)(?=</p>)/isU';
  80.     preg_match_all($preg$content$mb);
  81.     $str = strip_tags($mb[0][1]);
  82.     $str = str_replace(' '''$str);
  83.     $address = substr($str, 7);
  84.     if($address == '') {
  85.         $address = '未明';
  86.     }
  87.     return $address;
  88. }
  89. ?>

然后就是后台管理员的操作怎么弄了,主要是添加投票项的功能,操作数据库上面已经实现,后面的基本上是页面怎么设置,关系到js,添加投票项的页面是动态的,代码如下:

  1. function addVote()
  2. {
  3.     right.innerHTML="<h2>添加投票项</h2>";
  4.     right.innerHTML+="<label>投票项标签<label>";
  5.     addInput("right","cLabelName","地区名");
  6.     right.innerHTML+="<br><label>投票项名称<label>";
  7.     addInput("right","cSelectName","学校名");
  8.     right.innerHTML+="<br>";
  9.     var args = ''./add.php','cSelectName','cLabelName'';
  10.     var str = '<input type=button value="u6dfb加" onclick="goToPage('+args+');"/>';
  11.     right.innerHTML+=str;
  12. }
  13. //添加文本框
  14. function addInput(parent,id,pla)
  15. {
  16.     //创建input
  17.     var input = document.createElement("input");
  18.     input.type = "text";
  19.     input.id = id;
  20.     input.placeholder = pla;
  21.     document.getElementById(parent).appendChild(input);
  22. }

添加投票项是通过url传递变量到add.php页面的,代码如下:

  1. <?php
  2.     require_once '../api/func.php';
  3.     if (!isLoginNow())
  4.     {
  5.         goToPgae("./index.php");
  6.     }
  7.     $name = $_GET["cSelectName"];
  8.     $label = $_GET["cLabelName"];
  9.     //echo $name."<br>".$label;
  10.     require_once '../api/OperatorVotingDB.php';
  11.     $ovdb=new OperatorVotingDB();
  12.     $ovdb->addSelectName($name,$label);
  13.     require './header.htm';
  14.     goToPgae("./admin.php?page=add&auto="."$label"."&id=cLabelName&foc=cSelectName&msg=添加成功");
  15. ?>

下面是两个跳转页面的函数,js的,上面func.php中的跳转页面函数也是通过js实现的,代码如下:

  1. //js
  2. function goToPage(url,arg1,arg2)
  3. {
  4.     var a = document.getElementById(arg1).value;
  5.     var b = document.getElementById(arg2).value;
  6.     url += '?'+arg1+'='+a;
  7.     url += '&'+arg2+'='+b;
  8.     window.location.href=url;
  9. }
  10. function goToPage1(url)
  11. {
  12.     window.location.href=url;
  13. }

还有修改删除功能没有实现,我应该不会去实现那个了吧,js的话和添加功能差不多.

登录模块的话网上很多,模仿的,就是提交表单,查找数据库,返回结果,成功则设置cookie,后台的每个页面都添加了检测cookie的功能的.

给我留言

Copyright © 四季博客 保留所有权利.   Theme  Ality

用户登录