Онлайн-опрос и голосования с помощью PHP и MySQL

Онлайн-опросы используются для определения мнения пользователей. Их довольно часто можно встретить в интернете. И существует много сервисов, которые предоставляют услуги по организации голосования. Но если вы хотите создать собственный инструмент, это руководство вам поможет написать скрипт голосования.

В этой статье мы рассмотрим, как с помощью PHP создать простой скрипт опроса. Он использует PHP и MySQL для хранения в БД вариантов ответа, данных опроса и принятых голосов.

Функционал скрипта опроса

Данные опроса и варианты ответов хранятся в базе MySQL. Вопрос и варианты ответа будут извлекаться из базы данных, и выводиться пользователю. Он может выбрать вариант и отдать свой голос. Результаты голосования будут сохранены в базе данных с соответствующим вариантом ответа.

Кроме этого мы будем использовать PHP COOKIE, чтобы ограничить возможность повторного голосования. Результат опроса с общим подсчетом голосов и их количеством для каждого варианта ответа будут отображаться на странице. Результаты по вариантам ответа будут отображаться в виде процентной диаграммы.

Создание таблиц базы данных

В базе данных MySQL скрипта для голосования на сайте три таблицы: polls, poll_options и poll_votes.

Таблица polls содержит тему опроса или вопрос:

CREATE TABLE `polls` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `subject` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Таблица poll_options содержит варианты ответа и соответствующий идентификатор опроса:

CREATE TABLE `poll_options` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `poll_id` int(11) NOT NULL,
 `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1',
 PRIMARY KEY (`id`),
 KEY `poll_id` (`poll_id`),
 CONSTRAINT `poll_options_ibfk_1` FOREIGN KEY (`poll_id`) REFERENCES `polls` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Таблица poll_votes содержит результат подсчета голосов для варианта ответа, соответствующий идентификатор варианта ответа и идентификатор опроса:

CREATE TABLE `poll_votes` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `poll_id` int(11) NOT NULL,
 `poll_option_id` int(11) NOT NULL,
 `vote_count` bigint(10) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `poll_id` (`poll_id`),
 KEY `poll_option_id` (`poll_option_id`),
 CONSTRAINT `poll_votes_ibfk_1` FOREIGN KEY (`poll_id`) REFERENCES `polls` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
 CONSTRAINT `poll_votes_ibfk_2` FOREIGN KEY (`poll_option_id`) REFERENCES `poll_options` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Вставьте данные опроса и соответствующие варианты ответа в демонстрационную базу данных скрипта голосования:

INSERT INTO `polls` (`id`, `subject`, `created`, `modified`, `status`) VALUES
(1, 'Which is Your Favorite Website for PHP Programming?', '2016-11-07 04:13:13', '2016-11-07 04:13:13', '1');
INSERT INTO `poll_options` (`id`, `poll_id`, `name`, `created`, `modified`, `status`) VALUES
(1, 1, 'CodexWorld', '2016-11-07 11:29:31', '2016-11-07 11:29:31', '1'),
(2, 1, 'SitePoint', '2016-11-07 11:29:31', '2016-11-07 11:29:31', '1'),
(3, 1, 'Envato Tuts+', '2016-11-07 11:29:31', '2016-11-07 11:29:31', '1'),
(4, 1, 'Others', '2016-11-08 08:20:25', '2016-11-08 08:20:25', '1');

Класс Poll

Класс Poll используется для обработки запроса ко всей системе голосования и опросов. Этот класс выполняет следующие действия.

__construct() — подключает и выбирает базу данных.

getQuery() — выполняет SQL-запрос к базе данных MySQL и возвращает данные. Это закрытая функция, используемая только в этом классе.

getPolls() — получает опрос и соответствующие варианты ответа. Кроме этого он может получать данные нескольких опросов на основе запроса.

vote() — добавляет или обновляет количество полученных голосов в базе данных.

getResult() – эта функция PHP скрипта голосования предоставляет результаты опроса с количеством полученных голосов по каждому из вариантов ответа.

<?php
/*
 * Управляющий класс Poll 
 * Этот класс используется для управления системой онлайн опросов и голосований
 * @author    CodexWorld.com
 * @url       http://www.codexworld.com
 * @license   http://www.codexworld.com/license
 */
class Poll{
    private $dbHost  = 'localhost';
    private $dbUser  = 'root';
    private $dbPwd   = '';
    private $dbName  = 'poll_system';            
    private $db      = false;
    private $pollTbl = 'polls';
    private $optTbl  = 'poll_options';
    private $voteTbl = 'poll_votes';

    public function __construct(){
        if(!$this->db){ 
            // Устанавливаем соединение с базой данных
            $conn = new mysqli($this->dbHost, $this->dbUser, $this->dbPwd, $this->dbName);
            if($conn->connect_error){
                die("Failed to connect with MySQL: " . $conn->connect_error);
            }else{
                $this->db = $conn;
            }
        }
    }

    /*
     * Выполняем запрос к базе данных
     * @param строка SQL
     * @param строка count, single, all
     */
    private function getQuery($sql,$returnType = ''){
        $data = '';
        $result = $this->db->query($sql);
        if($result){
            switch($returnType){
                case 'count':
                    $data = $result->num_rows;
                    break;
                case 'single':
                    $data = $result->fetch_assoc();
                    break;
                default:
                    if($result->num_rows > 0){
                        while($row = $result->fetch_assoc()){
                            $data[] = $row;
                        }
                    }
            }
        }
        return !empty($data)?$data:false;
    }

    /*
     * Получаем данные опроса
     * Возвращаем данные одного или нескольких вопросов вместе с соответствующими им вариантами ответов
     * @param строка single, all
     */
    public function getPolls($pollType = 'single'){
        $pollData = array();
        $sql = "SELECT * FROM ".$this->pollTbl." WHERE status = '1' ORDER BY created DESC";
        $pollResult = $this->getQuery($sql, $pollType);
        if(!empty($pollResult)){
            if($pollType == 'single'){
                $pollData['poll'] = $pollResult;
                $sql2 = "SELECT * FROM ".$this->optTbl." WHERE poll_id = ".$pollResult['id']." AND status = '1'";
                $optionResult = $this->getQuery($sql2);
                $pollData['options'] = $optionResult;
            }else{
                $i = 0;
                foreach($pollResult as $prow){
                    $pollData[$i]['poll'] = $prow;
                    $sql2 = "SELECT * FROM ".$this->optTbl." WHERE poll_id = ".$prow['id']." AND status = '1'";
                    $optionResult = $this->getQuery($sql2);
                    $pollData[$i]['options'] = $optionResult;
                }
            }
        }
        return !empty($pollData)?$pollData:false;
    }

    /*
     * Подтверждаем ответ
     * @param массив вариантов ответов
     */
    public function vote($data = array()){
        if(!isset($data['poll_id']) || !isset($data['poll_option_id']) || isset($_COOKIE[$data['poll_id']])) {
            return false;
        }else{
            $sql = "SELECT * FROM ".$this->voteTbl." WHERE poll_id = ".$data['poll_id']." AND poll_option_id = ".$data['poll_option_id'];
            $preVote = $this->getQuery($sql, 'count');
            if($preVote > 0){
                $query = "UPDATE ".$this->voteTbl." SET vote_count = vote_count+1 WHERE poll_id = ".$data['poll_id']." AND poll_option_id = ".$data['poll_option_id'];
                $update = $this->db->query($query);
            }else{
                $query = "INSERT INTO ".$this->voteTbl." (poll_id,poll_option_id,vote_count) VALUES (".$data['poll_id'].",".$data['poll_option_id'].",1)";
                $insert = $this->db->query($query);
            }
            return true;
        }
    }

    /*
     * Получаем результаты опроса
     * @param ID опроса
     */
    public function getResult($pollID){
        $resultData = array();
        if(!empty($pollID)){
            $sql = "SELECT p.subject, SUM(v.vote_count) as total_votes FROM ".$this->voteTbl." as v LEFT JOIN ".$this->pollTbl." as p ON p.id = v.poll_id WHERE poll_id = ".$pollID;
            $pollResult = $this->getQuery($sql,'single');
            if(!empty($pollResult)){
                $resultData['poll'] = $pollResult['subject'];
                $resultData['total_votes'] = $pollResult['total_votes'];
                $sql2 = "SELECT o.id, o.name, v.vote_count FROM ".$this->optTbl." as o LEFT JOIN ".$this->voteTbl." as v ON v.poll_option_id = o.id WHERE o.poll_id = ".$pollID;
                $optResult = $this->getQuery($sql2);
                if(!empty($optResult)){
                    foreach($optResult as $orow){
                        $resultData['options'][$orow['name']] = $orow['vote_count']; 
                    }
                }
            }
        }
        return !empty($resultData)?$resultData:false;
    }
}

Представление опроса (index.php)

В этом файле скрипта голосование с выводом результатов отображается вопрос опроса и соответствующие варианты ответа. Для выбора варианта используется радио-кнопка. Внизу выводится кнопка «Отправить» и ссылка для просмотра результатов опроса:

<?php
    //Получаем данные опроса и вариантов ответов
    $pollData = $poll->getPolls();
?>
<div class="pollContent">
    <?php echo !empty($statusMsg)?'<p class="stmsg">'.$statusMsg.'</p>':''; ?>
    <form action="" method="post" name="pollFrm">
    <h3><?php echo $pollData['poll']['subject']; ?></h3>
    <ul>
        <?php foreach($pollData['options'] as $opt){
            echo '<li><input type="radio" name="voteOpt" value="'.$opt['id'].'" >'.$opt['name'].'</li>';
        } ?>
    </ul>
    <input type="hidden" name="pollID" value="<?php echo $pollData['poll']['id']; ?>">
    <input type="submit" name="voteSubmit" class="button" value="Vote">
    <a href="results.php?pollID=<?php echo $pollData['poll']['id']; ?>">Results</a>
    </form>
</div>

После того, как пользователь выбрал вариант ответа, голосование добавляется в базу данных с использованием класса Poll. Также используется PHP COOKIE, чтобы указать, что пользователь уже проголосовал, и какой статус должен отображаться пользователю:

<?php
//Включаем и инициализируем класс Poll 
include 'Poll.php';
$poll = new Poll;

//Проверяем, отправлен ли ответ
if(isset($_POST['voteSubmit'])){
    $voteData = array(
        'poll_id' => $_POST['pollID'],
        'poll_option_id' => $_POST['voteOpt']
    );
    //Оправляем результаты опроса с помощью класса Poll 
    $voteSubmit = $poll->vote($voteData);
    if($voteSubmit){ 
        //храним в $_COOKIE, чтобы отметить, что пользователь уже проголосовал
        setcookie($_POST['pollID'], 1, time()+60*60*24*365);
        $statusMsg = 'Your vote has been submitted successfully.';
    }else{
        $statusMsg = 'Your vote already had submitted.';
    }
}
?>

Результаты опроса (results.php)

В этом файле скрипта социального голосования для сайта результаты опроса извлекаются из базы данных и отображаются пользователю. Количество голосов для каждого варианта ответа преобразуется в процентный формат и выводится в виде процентной диаграммы:

<?php
// Включаем и инициализируем класс  class 
include 'Poll.php';
$poll = new Poll;
?>
<?php
//Получаем данные результатов опроса
$pollResult = $poll->getResult($_GET['pollID']);
?>
<h3><?php echo $pollResult['poll']; ?></h3>
<p><b>Total Votes:</b> <?php echo $pollResult['total_votes']; ?></p>
<?php
if(!empty($pollResult['options'])){ $i=0;
    //Массив цветов столбцов для каждого варианта ответа
    $barColorArr = array('azure','emerald','violet','yellow','red');
    //Общие параметры столбцов для вариантов ответа
    foreach($pollResult['options'] as $opt=>$vote){
        //Вычисляем процентное соотношение для каждого варианта ответа
        $votePercent = round(($vote/$pollResult['total_votes'])*100);
        $votePercent = !empty($votePercent)?$votePercent.'%':'0%';
        //Определяем цвет столбца
        if(!array_key_exists($i, $barColorArr)){
            $i=0;
        }
        $barColor = $barColorArr[$i];
?>
<div class="bar-main-container <?php echo $barColor; ?>">
  <div class="txt"><?php echo $opt; ?></div>
  <div class="wrap">
    <div class="bar-percentage"><?php echo $votePercent; ?></div>
    <div class="bar-container">
      <div class="bar" style="width: <?php echo $votePercent; ?>;"></div>
    </div>
  </div>
</div>
<?php $i++; } } ?>
<a href="index.php">Back To Poll</a>

Код CSS

В файле index.php используется следующий CSS-код для определения стилей темы и параметров опроса скрипта HTML на голосование:

.pollContent{
    float: left;
    width: 500px;
}
.pollContent h3 {
    font-size: 18px;
    color: #333;
    text-align: left;
    float: left;
    border-bottom: 2px solid #333;
    width: 100%;
    margin: 0 auto;
    padding-bottom: 10px;
}
.pollContent ul{
    list-style: none;
    float: left;
    width: 100%;
    padding: 10px;
}
.pollContent input[type="submit"], .pollContent a{
    border: none;
    font-size: 16px;
    color: #fff;
    border-radius: 3px;
    padding: 10px 15px 10px 15px; 
    background-color: #34a853;
    text-decoration: none;
    cursor: pointer;
}

В файле results.php используется следующий CSS-код для определения стилей результатов опроса с помощью скрипта социального голосования:

#container { text-align: center; margin: 20px; }
h2 { color: #CCC; }
a { text-decoration: none; color: #EC5C93; }
.bar-main-container {
    margin: 10px auto;
    width: 300px;
    height: 55px;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;
    font-family: sans-serif;
    font-weight: normal;
    font-size: 0.8em;
    color: #FFF;
}
.wrap { padding: 8px; }
.bar-percentage {
    float: left;
    background: rgba(0,0,0,0.13);
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;
    padding: 9px 0px;
    width: 18%;
    height: 16px;
    margin-top: -15px;
}
.bar-container {
    float: right;
    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    border-radius: 10px;
    height: 10px;
    background: rgba(0,0,0,0.13);
    width: 78%;
    margin: 0px 0px;
    overflow: hidden;
}
.bar-main-container .txt{
    padding-top: 5px;
    font-size: 16px;
    font-weight: bold;
}
.bar {
    float: left;
    background: #FFF;
    height: 100%;
    -webkit-border-radius: 10px 0px 0px 10px;
    -moz-border-radius: 10px 0px 0px 10px;
    border-radius: 10px 0px 0px 10px;
    -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
    filter: alpha(opacity=100);
    -moz-opacity: 1;
    -khtml-opacity: 1;
    opacity: 1;
}
/* ЦВЕТА */
.azure   { background: #38B1CC; }
.emerald { background: #2CB299; }
.violet  { background: #8E5D9F; }
.yellow  { background: #EFC32F; }
.red     { background: #E44C41; }

Заключение

В этой статье мы описали процесс создания простого скрипта для голосования HTML с помощью PHP и MySQL. Вы можете легко расширить этот простой скрипт. Это руководство призвано лишь помочь понять принцип создания модулей для голосования и разработать собственный вариант реализации.

Пожалуйста, оставьте ваши комментарии по текущей теме материала. За комментарии, лайки, отклики, дизлайки, подписки низкий вам поклон!

Данная публикация является переводом статьи «Online Poll and Voting System with PHP and MySQL» , подготовленная редакцией проекта.

Меню
Posting....