• 【PHP+MySQL】投票系统的设计和实现


    系统不大,完成这个系统的过程我分了三个步骤

    • 数据库设计
    • 系统框架设计
    • 前端美化

    数据库的设计

    设计三张表:投票结果统计表(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=\"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);
    }

    效果:

    image

    清空投票项也差不多,下过如下:

    image

    添加投票项是通过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的话我都是抄网上的。我弄的效果如下:

    image

    这个东西算是个很小的信息管理系统吧,我已经把这个东西的源代码放到github(https://github.com/hanxi/voting)上去了,可以随意下载修改。如果有想看看效果的话可以移步到http://www.jianhuanwang.com/huodong/Voting/

    欢迎读者回复交流,这方面不是我的强项,有很多不足之处还望指教。

  • 相关阅读:
    一个极好的ALV例子
    ABAP中读取文本文件(TXT DOCUMENT)并用ALV显示
    SMARTFORM报表程序设计(3)
    FOR ALL ENTRIES IN
    SMARTFORM报表程序设计(2)
    SMARTFORM报表程序设计(1)
    ABAP用FILE_OPEN_DIALOG打开多个文件后打印出名称
    LaTeX 表格的处理 [转]
    ubuntu安装deb,rpm安装包,tar.gz的方法 [转]
    OpenGL学习入门之VS2010环境配置 [转]
  • 原文地址:https://www.cnblogs.com/hanxi/p/2697512.html
Copyright © 2020-2023  润新知