2012-03-23 105 views
1

我有一個php/mysql民意調查,我想修改。PHP/MySQL民意調查 - 基於IP無重複投票

它設置了一個獨特的cookie,如果您已經投票並阻止您在同一輪投票中投票兩次(如果設置了cookie)。如果設置了,那麼你只能看到結果。

我想要做的是阻止用戶不止一次投票,如果他們的IP也在數據庫中(我知道會話會更好,但對我的情況不可能)。

我設法抓住IP並將其存儲在數據庫中,但我無法弄清楚告訴poll是否在數據庫中的邏輯。

有人能指出我正確的方向嗎?

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> 

回答

0

看上去彷彿所有的邏輯是在構造函數中,簡單地做對IP表的查詢爲用戶IP和QID,看看結果的數量大於0.如果是這樣,那麼就改變構造函數isset的最後一行($ _ COOKIE [$ this-> md5] || count($ res)> 0)? $ this-> poll(self :: VOTES):$ this-> poll(self :: POLL);

+0

謝謝。我會試試這個,稍後再報告。 – 2012-03-23 16:34:59

+0

這個技巧。謝了哥們。 – 2012-03-23 16:58:55