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

时间:2012-03-23 14:52:57

标签: php mysql pdo

我有一个我想修改的php / mysql民意调查。

如果您已经投票,它会设置一个唯一的Cookie,如果设置了Cookie,则阻止您在同一轮询中投票两次。如果设置了那么你只能看到结果。

我想做的是阻止用户多次投票,如果他们的IP也在数据库中(我知道会话会更好但不适用于我的情况)。

我已经设法获取IP并将其存储在数据库中但是我无法弄清楚告诉轮询它是否在数据库中的逻辑。

有人能指出我正确的方向吗?

cookie检测在构造函数和投票方法中。 cookie在投票方法结束时设置。

    <?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 = "\n</ul></fieldset>%button%\n%totalvotes%\n</form>\n";
        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;
        } 

    }
    ?>

以下是调查的实施方式:

    <?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 个答案:

答案 0 :(得分:0)

看起来好像你的所有逻辑都在构造函数中,只需针对用户ip和qid对ip表进行查询,看看结果的数量是否大于0.如果是,那么只需更改最后一行构造函数isset($ _ COOKIE [$ this-&gt; md5] || count($ res)&gt; 0)? $ this-&gt;民意调查(自我::投票):$ this-&gt;民意调查(自我:: POLL);