Онлайн-опрос и голосования с помощью 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» дружной командой проекта Сайтостроение от А до Я.

19 мая 2017 в 09:58
Материалы по теме
{"url":"http://www.fastvps.ru/", "src":"/images/advbanners/fastvps.png", "alt":"Хостинг Fastvps.ru. Наш выбор!"}
Заработок