pearweb_election
[ class tree: pearweb_election ] [ index: pearweb_election ] [ all elements ]

Source for file pear-voter.php

Documentation is available at pear-voter.php

  1. <?php
  2. require 'Text/Wiki.php';
  3. require_once 'Damblan/Karma.php';
  4.  
  5. class PEAR_Voter
  6. {
  7.     var $dbh;
  8.     var $user = false;
  9.     var $voteSalt;
  10.     var $damblan;
  11.     function __construct()
  12.     {
  13.         $this->dbh &$GLOBALS['dbh'];
  14.         $this->user = isset($GLOBALS['auth_user']$GLOBALS['auth_user']->handle : false;
  15.         $this->damblan = new Damblan_Karma($this->dbh);
  16.     }
  17.  
  18.     function listCurrentElections()
  19.     {
  20.         if ($this->user{
  21.             $all $this->dbh->getAll('
  22.                 SELECT
  23.                     IF(e.votestart > NOW(),"no","yes") as active,
  24.                     e.purpose,
  25.                     e.votestart,
  26.                     e.voteend,
  27.                     e.id
  28.                 FROM
  29.                     elections e
  30.                 WHERE
  31.                     e.votestart >= NOW() OR
  32.                      (e.votestart < NOW() AND e.voteend >= NOW())
  33.                 ORDER BY e.votestart
  34.             'array()DB_FETCHMODE_ASSOC);
  35.             foreach ($all as $i => $election{
  36.                 $vote $this->dbh->getOne('SELECT COUNT(*) FROM
  37.                     election_handle_votes
  38.                     WHERE election_id=? AND handle=?'array($election['id']$this->user));
  39.                 $all[$i]['voted'$vote 'yes' 'no';
  40.             }
  41.         else {
  42.             $all $this->dbh->getAll('
  43.                 SELECT
  44.                     IF(e.votestart > NOW(),"no","yes") as active,
  45.                     "no" as voted,
  46.                     e.purpose,
  47.                     e.votestart,
  48.                     e.voteend,
  49.                     e.id
  50.                 FROM
  51.                     elections e
  52.                 WHERE
  53.                     e.votestart >= NOW() OR
  54.                      (e.votestart < NOW() AND e.voteend >= NOW())
  55.                 ORDER BY e.votestart
  56.             'array()DB_FETCHMODE_ASSOC);
  57.         }
  58.         if (!is_array($all)) {
  59.             return array();
  60.         }
  61.         return $all;
  62.     }
  63.  
  64.     function listCompletedElections($old = false)
  65.     {
  66.         if ($old{
  67.             $extra '';
  68.         else {
  69.             $extra ' AND UNIX_TIMESTAMP() - UNIX_TIMESTAMP(e.voteend) < 2592000';
  70.         }
  71.         if ($this->user{
  72.             $all $this->dbh->getAll('
  73.                 SELECT
  74.                     e.purpose,
  75.                     e.votestart,
  76.                     e.voteend,
  77.                     e.id
  78.                 FROM
  79.                     elections e, election_results r
  80.                 WHERE
  81.                     e.id = r.election_id AND
  82.                     e.voteend < NOW()' $extra '
  83.                 GROUP BY e.id
  84.                 ORDER BY e.voteend DESC
  85.             'array()DB_FETCHMODE_ASSOC);
  86.             foreach ($all as $i => $election{
  87.                 $results $this->dbh->getAll('
  88.                     SELECT * FROM election_results
  89.                     WHERE election_id=? ORDER BY votepercent DESC
  90.                 'array($election['id'])DB_FETCHMODE_ASSOC);
  91.                 $vote $this->dbh->getOne('SELECT COUNT(*) FROM
  92.                     election_handle_votes
  93.                     WHERE election_id=? AND handle=?'array($election['id']$this->user));
  94.                 $all[$i]['voted'$vote 'yes' 'no';
  95.                 $all[$i]['results'$results;
  96.             }
  97.         else {
  98.             $all $this->dbh->getAll('
  99.                 SELECT
  100.                     "no" as voted,
  101.                     e.purpose,
  102.                     e.votestart,
  103.                     e.voteend,
  104.                     e.id,
  105.                     c.summary as winner,
  106.                     c.summary_link as winnerlink,
  107.                     e.id
  108.                 FROM
  109.                     elections e, election_choices c, election_results r
  110.                 WHERE
  111.                     e.id = r.election_id AND
  112.                     c.election_id = e.id AND
  113.                     e.voteend < NOW()' $extra '
  114.                 GROUP BY e.id
  115.                 ORDER BY e.voteend DESC
  116.             'array()DB_FETCHMODE_ASSOC);
  117.             foreach ($all as $i => $election{
  118.                 $results $this->dbh->getAll('
  119.                     SELECT * FROM election_results
  120.                     WHERE election_id=? ORDER BY votepercent DESC
  121.                 'array($election['id'])DB_FETCHMODE_ASSOC);
  122.                 $all[$i]['results'$results;
  123.             }
  124.         }
  125.         if (!is_array($all)) {
  126.             return array();
  127.         }
  128.         return $all;
  129.     }
  130.  
  131.     function listAllElections()
  132.     {
  133.         if (!$this->user{
  134.             return array();
  135.         }
  136.         $all $this->dbh->getAll('
  137.             SELECT
  138.                 e.purpose,
  139.                 e.id
  140.             FROM
  141.                 elections e, election_handle_votes v
  142.             WHERE
  143.                 v.election_id = e.id AND
  144.                 v.handle=?
  145.             ORDER BY e.voteend DESC
  146.         'array($this->user)DB_FETCHMODE_ASSOC);
  147.         if (!is_array($all)) {
  148.             return array();
  149.         }
  150.         return $all;
  151.     }
  152.  
  153.     function electionExists($id)
  154.     {
  155.         return $this->dbh->getOne('SELECT COUNT(id) FROM elections WHERE id=?'array($id));
  156.     }
  157.  
  158.     function electionInfo($id)
  159.     {
  160.         $info $this->dbh->getAll('
  161.             SELECT * FROM elections WHERE id = ?
  162.             'array($id)DB_FETCHMODE_ASSOC);
  163.         if (!is_array($info)) {
  164.             return false;
  165.         }
  166.         $info $info[0];
  167.         $choices $this->dbh->getAll('
  168.             SELECT * FROM election_choices WHERE election_id = ?
  169.             ORDER BY choice
  170.             'array($id)DB_FETCHMODE_ASSOC);
  171.         $info['choices'$choices;
  172.         $info['results'$this->dbh->getAll('
  173.             SELECT e.votepercent, e.votetotal, c.choice, c.summary, c.summary_link
  174.             FROM election_results e, election_choices c
  175.             WHERE e.election_id = ? AND
  176.                 c.election_id = e.election_id AND
  177.                 c.choice = e.choice
  178.             ORDER BY e.votetotal DESC
  179.         'array($id)DB_FETCHMODE_ASSOC);
  180.  
  181.         // calculate winners
  182.         $order = array();
  183.         foreach ($info['results'as $result{
  184.             $order[$result['votetotal']][$result;
  185.         }
  186.         krsort($orderSORT_NUMERIC);
  187.         $winners = array();
  188.         foreach ($order as $results{
  189.             if (count($winners>= $info['maximum_choices']{
  190.                 break; // done
  191.             }
  192.             foreach ($results as $result{
  193.                 $winners[$result['choice'];
  194.             }
  195.         }
  196.         $info['winners'$winners;
  197.  
  198.         $abstain $this->dbh->getOne('
  199.             SELECT COUNT(*) FROM election_votes_abstain
  200.             WHERE election_id=?
  201.         'array($id));
  202.         $allvoters $this->dbh->getOne("
  203.         SELECT
  204.             COUNT(DISTINCT k.user)
  205.         FROM karma k, users u
  206.         WHERE
  207.             k.user = u.handle AND
  208.             k.level in ('pear.dev', 'pear.voter', 'pear.admin')"array());
  209.         $votedthis $this->dbh->getOne('
  210.         SELECT count(*) FROM election_handle_votes where election_id=?
  211.         'array($id));
  212.         $info['turnout'$votedthis $allvoters;
  213.         $wiki =new Text_Wiki();
  214.         $wiki->disableRule('wikilink');
  215.         $info['detail'$wiki->transform($info['detail']);
  216.         if ($info['maximum_choices'> 1{
  217.             $total $this->dbh->getOne('
  218.                 SELECT COUNT(*) FROM election_votes_multiple WHERE
  219.                 election_id=?
  220.             'array($id));
  221.         else {
  222.             $total $this->dbh->getOne('
  223.                 SELECT COUNT(*) FROM election_votes_single WHERE
  224.                 election_id=?
  225.             'array($id));
  226.         }
  227.         // percentage of abstaining voters
  228.         if ($total $abstain > 0{
  229.             $info['abstain'$abstain ($total $abstain);
  230.             $info['abstaincount'$abstain;
  231.         else {
  232.             $info['abstain'= 0;
  233.             $info['abstaincount'= 0;
  234.         }
  235.         return $info;
  236.     }
  237.  
  238.     function hasVoted($id)
  239.     {
  240.         return $this->dbh->getOne('
  241.             SELECT COUNT(*) FROM election_handle_votes WHERE election_id=?
  242.             AND handle=?'array($id$this->user));
  243.     }
  244.  
  245.     function pendingElection($id)
  246.     {
  247.         $info $this->electionInfo($id);
  248.         if (strtotime($info['votestart']time(> 0 &&
  249.               time(strtotime($info['voteend']> 0{
  250.             // election is not active
  251.             return true;
  252.         }
  253.         return false;
  254.     }
  255.  
  256.     function canVote($id)
  257.     {
  258.         if ($this->hasVoted($id)) {
  259.             return false;
  260.         }
  261.         $info $this->electionInfo($id);
  262.         if (strtotime($info['votestart']time(> 0{
  263.             // election is not active
  264.             return false;
  265.         }
  266.         if (strtotime($info['voteend''+1 day'time(< 0{
  267.             // election is finished
  268.             return false;
  269.         }
  270.         if ($info['eligiblevoters'== 1{
  271.             // PEAR developers
  272.             if ($this->damblan->has($this->user'pear.dev')) {
  273.                 return true;
  274.             }
  275.             return false;
  276.         elseif ($info['eligiblevoters'== 2{
  277.             // general PHP public + PEAR developers
  278.             if ($this->damblan->has($this->user'pear.dev')) {
  279.                 return true;
  280.             }
  281.             if ($this->damblan->has($this->user'pear.voter')) {
  282.                 return true;
  283.             }
  284.             return false;
  285.         }
  286.         return false;
  287.     }
  288.  
  289.     function getVoteSalt()
  290.     {
  291.         if (!isset($this->voteSalt)) {
  292.             $this->voteSalt date('YmdHis'mt_rand(1999);
  293.         }
  294.         return $this->voteSalt;
  295.     }
  296.  
  297.     function vote($id$votes)
  298.     {
  299.         if (!$this->user{
  300.             return false;
  301.         }
  302.         if (!$this->electionExists($id)) {
  303.             return false;
  304.         }
  305.         if ($this->hasVoted($id)) {
  306.             return false;
  307.         }
  308.         if (!is_array($votes)) {
  309.             return false;
  310.         }
  311.         $info $this->electionInfo($id);
  312.         if ($info['maximum_choices'> 1{
  313.             if (count($votes$info['maximum_choices'|| count($votes<
  314.                   $info['minimum_choices']{
  315.                 return false;
  316.             }
  317.             $table 'election_votes_multiple';
  318.         else {
  319.             if (count($votes!= 1{
  320.                 return false;
  321.             }
  322.             $table 'election_votes_single';
  323.         }
  324.         $vote_hash md5($this->user $this->getVoteSalt());
  325.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  326.         foreach ($votes as $vote{
  327.             $err $this->dbh->query('
  328.                     INSERT INTO ' $table '
  329.                       (election_id, vote, vote_hash)
  330.                       VALUES(?,?,?)'array($id$vote$vote_hash));
  331.             if (PEAR::isError($err)) {
  332.                 // "rollback" the query
  333.                 $this->dbh->query('DELETE FROM ' $table '
  334.                     WHERE election_id=? AND vote_hash=?'array($id$vote_hash));
  335.                 PEAR::popErrorHandling();
  336.                 return false;
  337.             }
  338.         }
  339.         $err $this->dbh->query('
  340.             INSERT INTO election_handle_votes
  341.                 (election_id, handle) VALUES (?,?)'array($id$this->user));
  342.         if (PEAR::isError($err)) {
  343.             // "rollback" the query
  344.             $this->dbh->query('DELETE FROM ' $table '
  345.                 WHERE election_id=? AND vote_hash=?'array($id$vote_hash));
  346.             $this->dbh->query('DELETE FROM election_handle_votes
  347.                 WHERE election_id=? AND handle=?'array($id$this->user));
  348.             PEAR::popErrorHandling();
  349.             return false;
  350.         }
  351.         PEAR::popErrorHandling();
  352.         $this->email($info$votes$this->getVoteSalt());
  353.         return true;
  354.     }
  355.  
  356.     function prettifyVotes($election$votes)
  357.     {
  358.         $res '';
  359.         foreach ($election['choices'as $choice{
  360.             if (in_array($choice['choice']$votes)) {
  361.                 $res .= '[X] ';
  362.             else {
  363.                 $res .= '[ ] ';
  364.             }
  365.             $res .= $choice['summary'"\n";
  366.         }
  367.         return $res;
  368.     }
  369.  
  370.     function email($election$votes$salt)
  371.     {
  372.         include_once 'pear-database-user.php';
  373.         $info = user::info($this->user);
  374.         $email '"' $info['name''" <' $info['email''>';
  375.         $headers "From: bounce-no-user@php.net\n";
  376.         $headers .= "X-Mailer: PEAR election voting interface\n";
  377.         $headers .= "X-PEAR-Election: " $election['id'"\n";
  378.  
  379.         $subject '[PEAR-ELECTION] Your vote in election ' $election['purpose'];
  380.  
  381.         if ($votes{
  382.             $votes $this->prettifyVotes($election$votes);
  383.             $text 'Your vote for the election: ' $election['purpose'"\n" .
  384.                 'has been registered.  You voted for:
  385. ';
  386.             $text .= $votes "\n";
  387.             $text .= 'Your vote salt is ' $salt "\n";
  388.             $text .= 'this is your only record of the vote salt, without it your vote ' .
  389.                 'cannot be retrieved.  Thank you for voting';
  390.         else {
  391.             $text 'Your abstaining vote for the election: ' $election['purpose'"\n" .
  392.                 'has been registered.' "\n";
  393.             $text .= 'Your vote salt is ' $salt "\n";
  394.             $text .= 'this is your only record of the vote salt, without it your vote ' .
  395.                 'cannot be retrieved.  Thank you for voting';
  396.         }
  397.         $text .= "\nVisit http://pear.php.net/election/ to retrieve your vote";
  398.  
  399.         $res mail($email$subject$text,
  400.                     $headers'-f bounce-no-user@php.net');
  401.         return $res;
  402.     }
  403.  
  404.     function abstain($id)
  405.     {
  406.         if (!$this->user{
  407.             return false;
  408.         }
  409.         if (!$this->electionExists($id)) {
  410.             return false;
  411.         }
  412.         if ($this->hasVoted($id)) {
  413.             return false;
  414.         }
  415.         $vote_hash md5($this->user $this->getVoteSalt());
  416.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  417.         $err $this->dbh->query('
  418.             INSERT INTO election_votes_abstain
  419.                 (election_id, vote_hash) VALUES (?,?)'array($id$vote_hash));
  420.         if (PEAR::isError($err)) {
  421.             PEAR::popErrorHandling();
  422.             return false;
  423.         }
  424.         $err $this->dbh->query('
  425.             INSERT INTO election_handle_votes
  426.                 (election_id, handle) VALUES (?,?)'array($id$this->user));
  427.         if (PEAR::isError($err)) {
  428.             $this->dbh->query('DELETE FROM election_votes_abstain
  429.                 WHERE election_id=? and vote_hash=?'array($id$vote_hash));
  430.             PEAR::popErrorHandling();
  431.             return false;
  432.         }
  433.         PEAR::popErrorHandling();
  434.         $this->email($this->electionInfo($id)false$this->getVoteSalt());
  435.         return true;
  436.     }
  437.  
  438.     function retrieveVote($id$salt)
  439.     {
  440.         if (!$this->electionExists($id)) {
  441.             return false;
  442.         }
  443.         if (!$this->user{
  444.             return false;
  445.         }
  446.         if (!$this->hasVoted($id)) {
  447.             return false;
  448.         }
  449.         $this->voteSalt md5($this->user $salt);
  450.         if ($vote $this->dbh->getOne('
  451.              SELECT * FROM election_votes_abstain WHERE election_id=? AND vote_hash=?',
  452.              array($id$this->voteSalt))) {
  453.             return array('(abstain)');
  454.         }
  455.         if ($vote $this->dbh->getOne('
  456.              SELECT choice FROM election_votes_single e, election_choices c
  457.               WHERE e.election_id=?
  458.               AND e.vote_hash=?
  459.               AND e.election_id = c.election_id
  460.               AND e.vote = c.choice'array($id$this->voteSalt))) {
  461.             return array($vote);
  462.         }
  463.         $votes $this->dbh->getAll('
  464.             SELECT choice FROM election_votes_multiple e, election_choices c
  465.              WHERE e.election_id=?
  466.              AND e.vote_hash=?
  467.              AND e.election_id = c.election_id
  468.              AND e.vote = c.choice'array($id$this->voteSalt));
  469.         $ret = array();
  470.         foreach ($votes as $vote{
  471.             $ret[$vote[0];
  472.         }
  473.         if (!$ret{
  474.             return false;
  475.         }
  476.         return $ret;
  477.     }
  478. }

Documentation generated on Mon, 11 Mar 2019 15:34:36 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.