doubei5310 2012-03-23 14:52
浏览 60
已采纳

PHP / MySQL民意调查 - 不基于IP重复投票

I have a php/mysql poll that I'm trying to modify.

It sets a unique cookie if you've voted and blocks you from voting twice on the same poll if the cookie is set. If it set then you can only see the results.

What I would like to do is block the user from voting more than once if their IP is in the database as well (I know sessions would be better but not possible for my situation).

I've managed to grab the IP and store it in the db but I can't figure out the logic to tell the poll if it's in the database or not.

Can someone point me in the right direction?

The cookie detection is in the constructor and vote methods. The cookie is set at the end of the vote method.

    <?php
    # don't display errors
    ini_set('display_errors',0);
    error_reporting(E_ALL|E_STRICT); 

    class webPoll {

        # makes some things more readable later
        const POLL = true;
        const VOTES = false;

        # number of pixels for 1% on display bars
        public $scale = 2;
        public $question = '';
        public $answers = array();

        private $header = '<form class="webPoll" method="post" action="%src%">
                           <input type="hidden" name="QID" value="%qid%"/>
                           <h4>%question%</h4>
                           <fieldset><ul>';
        private $center = '';
        private $footer = "
</ul></fieldset>%button%
%totalvotes%
</form>
";
        private $button = '<p class="buttons"><button type="submit" class="vote">Vote!</button></p>';
        private $totalvotes = '';
        private $md5 = '';
        private $id = '';

        /**
         * ---
         * Takes an array containing the question and list of answers as an
         * argument. Creates the HTML for either the poll or the results depending
         * on if the user has already voted
         */
        public function __construct($params) {
            $this->id = array_shift($params);
            $this->question = array_shift($params);
            $this->answers = $params;
            $this->md5 = md5($this->id);
            $this->header = str_replace('%src%', $_SERVER['SCRIPT_NAME'], $this->header);
            $this->header = str_replace('%qid%', $this->md5, $this->header);
            $this->header = str_replace('%question%', $this->question, $this->header);

            # seperate cookie for each individual poll (has the user voted yet?)
            # if cookie is set then show results(VOTES), if not then let user vote(POLL)
            isset($_COOKIE[$this->md5]) ? $this->poll(self::VOTES) : $this->poll(self::POLL); 
        }
        private function poll($show_poll) {
            $replace_btn = $show_poll ? $this->button : '';
            $get_results = webPoll::getData($this->md5);
            $total_votes = array_sum($get_results);
            $replace_votes = $show_poll ? $this->totalvotes : '<small>Total Votes: '.$total_votes.'</small>';

            $this->footer = str_replace('%button%', $replace_btn, $this->footer);
            $this->footer = str_replace('%totalvotes%', $replace_votes, $this->footer);

            # static function doesn't have access to instance variable
            if(!$show_poll) {
                $results = webPoll::getData($this->md5);
                $votes = array_sum($results);
            }

            for( $x=0; $x<count($this->answers); $x++ ) {
                $this->center .= $show_poll ? $this->pollLine($x) : $this->voteLine($this->answers[$x],$results[$x],$votes);
            }
            echo $this->header, $this->center, $this->footer;
        }
        private function pollLine($x) {
            isset($this->answers[$x+1]) ? $class = 'bordered' : $class = '';
            return "
            <li class='$class'>
                    <label class='poll_active'>
                    <input type='radio' name='AID' value='$x' />
                        {$this->answers[$x]}
                    </label>
            </li>
        ";
        }
        private function voteLine($answer,$result,$votes) {
            $result = isset($result) ? $result : 0;
            $percent = round(($result/$votes)*100);
            $width = $percent * $this->scale;
            return "
            <li>
                    <div class='result' style='width:{$width}px;'>&nbsp;</div>{$percent}%
                    <label class='poll_results'>
                        $answer
                    </label>
            </li>
        ";
        }
        /**
         * processes incoming votes. votes are identified in the database by a combination
         * of the question's MD5 hash, and the answer # ( an int 0 or greater ).
         */
        static function vote() {

            if(!isset($_POST['QID']) || !isset($_POST['AID']) || isset($_COOKIE[$_POST['QID']])) {
                # leave vote method if any of the above are true
                return;
            }

            $dbh = new PDO('mysql:host=????;dbname=????', '????', '');
            $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

            try {
                # add vote info to 'tally' table
                $sth = $dbh->prepare("INSERT INTO tally (QID,AID,votes,created_at) values (?, ?, 1, NOW())");
                $ex = array($_POST['QID'],$_POST['AID']);
                $sth->execute($ex);
                # add ip info to 'ips' table
                $sth2 = $dbh->prepare("INSERT INTO ips (ips,QID,AID) values (?,?,?)");
                $ex2 = array($_SERVER['REMOTE_ADDR'],$_POST['QID'],$_POST['AID']);
                $sth2->execute($ex2);
            }
            catch(PDOException $e) {
                # 23000 error code means the key already exists, so UPDATE! 
                if($e->getCode() == 23000) {
                    try {
                        # update number of votes for answers in 'tally' table
                        $sth = $dbh->prepare("UPDATE tally SET votes = votes+1 WHERE QID=? AND AID=?");
                        $sth->execute(array($_POST['QID'],$_POST['AID']));
                        # add ip info to 'ips' table
                        $sth2 = $dbh->prepare("INSERT INTO ips (ips,QID,AID) values (?,?,?)");
                        $ex2 = array($_SERVER['REMOTE_ADDR'],$_POST['QID'],$_POST['AID']);
                        $sth2->execute($ex2);
                    }
                    catch(PDOException $e) {
                        webPoll::db_error($e->getMessage());
                    }
                }
                else {
                    webPoll::db_error($e->getMessage());
                }
            }

            # entry in $_COOKIE to signify the user has voted, if he has
            if($sth->rowCount() == 1) {
                setcookie($_POST['QID'], 1, time()+60*60*24*365, '/', '', FALSE, TRUE);
                $_COOKIE[$_POST['QID']] = 1;
            }
        }
        static function getData($question_id) {
            try {
                $dbh = new PDO('mysql:host=????;dbname=????', '????', '');
                $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

                $STH = $dbh->prepare('SELECT AID, votes FROM tally WHERE QID = ?');
                $STH->execute(array($question_id));
            }
            catch(PDOException $e) {  
                # Error getting data, just send empty data set
                return array(0); 
            }

            while($row = $STH->fetch()) {
                $results[$row['AID']] = $row['votes'];   
            }

            return $results;
        }
        /*
         * You can do something with the error message if you like. Email yourself
         * so you know something happened, or make an entry in a log
         */
        static function db_error($error) {   
            echo "A database error has occurred. $error";
            exit;
        } 

    }
    ?>

And here's how the poll is implemented:

    <?php
        ini_set('display_errors',1);
        error_reporting(E_ALL|E_STRICT);

        include('webPoll-hiddenMD5.class.php');
        webPoll::vote();    
    ?>
    <html>
    <head>
        <title>Poll Test</title>
        <link rel="stylesheet" href="poll.css" type="text/css" />
        <!--[if IE]>
        <style> body { behavior: url("res/hover.htc"); } </style>
        <![endif]-->
    </head>
    <body>
    <?php

        $a1 = new webPoll(array(
                'March 16, 2012 What subjects would you like to learn more about?',            
                'What subjects would you like to learn more about?',
                'HTML & CSS',
                'Javascript',
                'JS Frameworks (Jquery, etc)',
                'Ruby/Ruby on Rails',
                'PHP',
                'mySQL'));

    ?>
    </body>
    </html>
  • 写回答

1条回答 默认 最新

  • dos3018 2012-03-23 15:10
    关注

    Looks as if all your logic is in the constructor, simply do a query against the ip table for the users ip and qid and see if the number of results is greater then 0. If so then just change the last line of the constructor isset($_COOKIE[$this->md5] || count($res)>0 ) ? $this->poll(self::VOTES) : $this->poll(self::POLL);

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 高价邀请复制 域天d8联网狗
  • ¥15 本题的答案是不是有问题
  • ¥15 关于#r语言#的问题:(svydesign)为什么在一个大的数据集中抽取了一个小数据集
  • ¥15 C++使用Gunplot
  • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 蓝桥杯单片机第十三届第一场,整点继电器吸合,5s后断开出现了问题
  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?