• HTML
  • CSS
  • JavaScript
  • PHP

Как сделать голосовалку для сайта на PHP?

Приветствую!

Мне необходимо разместить на сайте небольшую голосовалку. Возможно, ли это реализовать на простом HTML-сайте (без использования движка)? Если да, то как?

Комментарии: 10

Константин
Константин
Приветствую, спасибо за скрипт. единственный вопрос с накруткой голосов, COOKIE не очень хорошо работают, может возможно добавить защиту по IP?
Daler
Daler
Добрый день. Переменная $current — отвечает за то какой pool — опрос отображается. Не подскажите как сделать переключатель ввиде далее между опросами? И как добавить больше вопросов и ответов в 1 опрос, буду очень признателен
Александр Мальцев
Александр Мальцев
Как можно создать опросы на сайте, которые сохраняют данные не в базу, а в обычный текстовый файл...
Данная инструкция пригодиться не только тем, у кого нет CMS, но и тем, у кого она есть. Кроме этого данный вариант может также пригодиться тем, у кого имеются высоконагруженные сайты, т.к. предложенная голосовалка для сайта практически не будет создавать нагрузку на процессор, а базу данных она вообще не использует.
Работать созданная система опроса на сайте будет через AJAX и использовать COOKIE (для защиты от накрутки).

Скриншоты, т.е. как будет выглядеть блока опроса и его результаты на сайте:
Форма для голосования -1Результаты формы для голосования -1
Форма для опроса -2Результаты формы для голосования -2

Формат хранения результатов на сервере (JSON):
{"pool-1":[3,2,5,2],"pool-2":[0,2,3,1,0]}
Как подключить голосовалку к страницам сайта:
1. Вставить в необходимую часть страницы следующий HTML-код голосовалки (оформление формы выполнено с помощью стилей Bootstrap):
<section class="panel panel-danger">
  <div class="panel-heading">
    <h3 class="panel-title">
      Голосование
    </h3>
  </div>
  <div class="panel-body"> 
    <!-- HTML-структура голосовалки -->
    <div class="question"></div>
    <hr>
    <div id="vote-section">              
      <form id="vote" action="poll-vote.php" method="POST">
        <div class="answers"></div>
        <button type="submit" class="btn btn-default" disabled="disabled">Голосовать</button>
      </form>
    </div>
    <!-- конец HTML-структура -->
  </div>
</section>
Внимание: В HTML коде необходимо указать путь к файлу poll-vote.php (если конечно он не находится в той же директории, в которой расположена и страница).
Если на сайте не используется Bootstrap, то тогда необходимо написать стили для оформления опроса и результатов голосования.
2. Вставить следующий фрагмент сценария JavaScript на страницу (после подключения jQuery):
<script>
  $(function(){
  
    var pathToPolls = 'polls.php';
    
    var vote = {};
    $.get(pathToPolls, function(data) {
      
      var data = JSON.parse(data);
      vote['id']=data['id'];
      vote['question']=data['question'];
      vote['answers']=data['answers'];

      if (data.hasOwnProperty('result')) {
        $('#vote').parent().parent().find('.question').text(vote['question']);
        var _answers = vote['answers'];
        var output = '';
        var result = data['result'];
        var totalvotes = 0;
        for (var i=0; i <= result.length-1; i++) {
          totalvotes += result[i];
        }
        for (var i=0; i <= result.length-1; i++) {
          output += '<p style="margin:0px;">'+_answers[i]+'</p>'+
            '<p class="text-right" style="margin:0px;"><b>'+((result[i]/totalvotes)*100).toFixed(1)+'%</b> (Голосов: '+result[i]+')</p>'+
            '<div class="progress">'+
              '<div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" aria-valuenow="'+(result[i]/totalvotes)*100+'" aria-valuemin="0" aria-valuemax="100" style="width: '+(result[i]/totalvotes)*100+'%">'+
                '<span class="sr-only">'+(result[i]/totalvotes)*100+'%</span>'+
              '</div>'+
            '</div>';
        }
        $('#vote-section').html(output);
      } else {          
        processPoll();
      }
    });    

    var processPoll = function() {        
      var _id = vote['id'];
      var _answers = vote['answers'];
      var form = $('#vote');
      form.parent().parent().find('.question').text(vote['question']);
      form.prepend('<input type="hidden" name="count" value="'+vote['answers'].length+'">');
      form.prepend('<input type="hidden" name="id" value="'+vote['id']+'">');
      var answers = form.find('.answers');
      for (var i=0; i<=vote['answers'].length-1;i++) {
        answers.append('<div class="radio">'+
            '<label>'+
              '<input type="radio" name="poll" value="'+(i+1)+'">'+
              vote['answers'][i]+
            '</label>'+
          '</div>');
      }
      if (form.find('button[type="submit"]:disabled')) { 
        form.find('input[type="radio"]').click(function(){
          form.find('button[type="submit"]').prop('disabled',false);
          form.find('input[type="radio"]').off('click');  
        });          
      };
      
      form.submit(function(e) {
        //отмена действия по умолчанию для кнопки submit
        e.preventDefault();
        $.post(form.attr('action'), form.serializeArray(), function(data) {
          if (data) {
            var data = JSON.parse(data);
            var output = '';
            var result = data[_id];
            var totalvotes = 0;
            for (var i=0; i <= result.length-1; i++) {
              totalvotes += result[i];
            }
            for (var i=0; i <= result.length-1; i++) {
              output += '<p style="margin:0px;">'+_answers[i]+'</p>'+
                '<p class="text-right" style="margin:0px;"><b>'+((result[i]/totalvotes)*100).toFixed(1)+'%</b> (Голосов: '+result[i]+')</p>'+
                '<div class="progress">'+
                  '<div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" aria-valuenow="'+(result[i]/totalvotes)*100+'" aria-valuemin="0" aria-valuemax="100" style="width: '+(result[i]/totalvotes)*100+'%">'+
                    '<span class="sr-only">'+(result[i]/totalvotes)*100+'%</span>'+
                  '</div>'+
                '</div>';
            }
            $('#vote-section').html(output);
          }
        }); 
      });
    };

  });
</script>
В переменной pathToPolls указать путь к файлу polls.php.
3. На сервере…
На сервере используются 2 файла php (polls.php и poll-vote.php).

В файле polls.php хранятся все опросы в формате ассоциативного массива (каждый опрос – это объект).
Синтаксис опроса:
// pool-1
$key = 'pool-1';
$value = new stdClass();
$value->id = $key;
$value->question = 'Какая стихия вам ближе?';
$value->answers = array('Огонь','Воздух','Вода','Земля');
$votes[$key]=$value;
Для того чтобы добавить новый опрос, необходимо продублировать этот код и ввести необходимые значения в соответствующие переменные.
Установка, какой опрос показывать на страницах управляется с помощью значения переменной $current.
$current = 'pool-1';
Это очень удобно, т.к. ничего не надо править на страницах. Т.е. для того чтобы установить показ другого опроса на всех страницах сайта достаточно будет просто указать необходимый ключ опроса в качестве значения этой переменной.
Также этот файл возвращает результаты, если пользователь уже проголосовал на сайте (для этого используются COOKIE).

Второй файл (poll-vote.php) записывает данные голосования в файл poll-results.txt, который создаётся по умолчанию в той же директории, в которой расположены эти 2 php файла. В качестве формата данных используется ассоциативный массив. Кроме этого данный файл после того как пользователь проголосовал ещё возвращает результаты голосования (в качестве ответа).

Код файла polls.php:
<?php
$nameFile = 'poll-results.txt';
$current = 'pool-2';

$votes = array();

// pool-1
$key = 'pool-1';
$value = new stdClass();
$value->id = $key;
$value->question = 'Какая стихия вам ближе?';
$value->answers = array('Огонь','Воздух','Вода','Земля');
$votes[$key]=$value;

// pool-2
$key = 'pool-2';
$value = new stdClass();
$value->id = $key;
$value->question = 'Какой ваш любимый цвет?';
$value->answers = array('Красный','Оранжевый','Зелёный','Синий','Нет, другой');
$votes[$key]=$value;


/* блок для вывода результатов если пользователь проголосовал */
if (isset($_COOKIE['polls'])) {
  $arrayPolls = explode(',',$_COOKIE['polls']);
  if (in_array($current, $arrayPolls)) {
    // получаем содержимое файла
    $output = file_get_contents(dirname(__FILE__).'/'.$nameFile);
    // декодируем содержимое в массив
    $output = json_decode($output, true);
    // проверяем есть если указанный ключ голосования в ассоциативном массиве
    if (array_key_exists($current, $output)) {
      // получаем значение, связанное с указанным ключом
      $votes[$current]->result = $output[$current];
    }
  }
}

echo json_encode($votes[$current]);

exit();
Код файла poll-vote.php:
<?php
// Если  запрос не AJAX (XMLHttpRequest), то завершить работу
if (empty($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {return;}

if (empty($_POST['id'])) {exit();}

$nameFile = 'poll-results.txt';

$id = $_POST['id'];
$answer = $_POST['poll'];
$count = $_POST['count'];

if (isset($_COOKIE['polls'])) {
  $arrayPolls = explode(',',$_COOKIE['polls']);
  if (in_array($id, $arrayPolls)) {
    exit();
  }
}


// массив, который будем возвращать клиенту
$result = array();

// если файлами с результатами нет
if (!file_exists($nameFile)) {
  // результирующий массив
  $output = array();
  // массив для хранения ответов
  $answers = array();
  // заполняем массив нулями
  for ($i=0; $i<=$count-1; $i++) {
    $answers[$i] = 0;
  }
  // увеличиваем в массиве полученный элемент на 1
  $answers[$answer-1] = $answers[$answer-1] + 1;
  // связываем id опроса с ответами   
  $output[$id] = $answers;
  // кодируем ассоциативный массив в JSON
  $output = json_encode($output);
  // записываем в файл
  file_put_contents(dirname(__FILE__).'/'.$nameFile, $output, LOCK_EX);
} else {
  // получаем содержимое файла
  $output = file_get_contents(dirname(__FILE__).'/'.$nameFile);
  // декодируем содержимое в массив
  $output = json_decode($output, true);
  // проверяем есть если указанный ключ голосования в ассоциативном массиве
  if (array_key_exists($id, $output)) {
    // получаем значение, связанное с указанным ключом
    $answers = $output[$id];
    // увеличиваем в массиве полученный элемент на 1
    $answers[$answer-1] = $answers[$answer-1] + 1;
    // перезеписываем массив ответов, связанных с ключом
    $output[$id] = $answers;
  } else {
    /* если не найден переданный ключ в массиве */
    // массив для хранения ответов
    $answers = array();
    // заполняем массив нулями
    for ($i=0; $i<=$count-1; $i++) {
      $answers[$i] = 0;
    }
    // увеличиваем в массиве полученный элемент на 1
    $answers[$answer-1] = $answers[$answer-1] + 1;
    // добавляем в результирующий массив ключом и связанный с ним ассоциативный массив
    $output[$id] = $answers;
  }
  // кодируем ассоциативный массив в JSON
  $output = json_encode($output);
  // записываем в файл
  file_put_contents(dirname(__FILE__).'/'.$nameFile, $output, LOCK_EX);
}

if (isset($_COOKIE['polls'])) {
  $arrayPolls = explode(',',$_COOKIE['polls']);
} else {
  $arrayPolls = array();
}
array_push($arrayPolls,$id);
setcookie('polls', implode(',',$arrayPolls),time() + (86400 * 365),'/');   

$result[$id] = $answers;
$result = json_encode($result);  
echo $result;
exit();
?>
Скачать готовый пример можно с Яндекс Диска.
Проект на Githib: github.com/itchief/simple-poll
Андрей
Андрей
Александр спасибо, отличный вариант. Обязательно попробую в действии.
Иван Шеин
Иван Шеин
Здравствуйте. Такой вопрос — можно ли сделать так, чтобы, помимо того, чтобы записывалось в текстовый файл, ещё скидывался результат на указанную почту? Ну или вместо файла результаты на почту.
Я предполагаю, что для этого надо в php файле poll-vote.php изменить или добавить параметры для отправки на почту.
Но к сожалению знаний мне для этого ещё не достаточно. Подскажите, мои рассуждения верны? И, если верны, прошу подсказать, что и куда вписать)
Иван Шеин
Иван Шеин
А так же вопрос касаемо тайминга. Т.е. мне надо, чтобы опросы сбрасывались во вторник после 20:00, в четверг после 20:00 и в субботу. Так же после 20:00.
Если это, конечно, возможно.
Александр Мальцев
Александр Мальцев
Привет! Чтобы это реализовать, лучше создать новый php-файл, который будет брать данные из «poll-results.txt», формировать нужное тело письма и отправлять его адресатам. Запускать этот файл можно через планировщика cron (обычно имеется на всех виртуальных хостингах), указав в нём нужные дни и нужное время.
Иван Шеин
Иван Шеин
А подскажете, как это сделать? А то я недавно в программировании. Освоил пока HTML, по нужде залез в CSS, но Java и php для меня пока тёмный лес(
Александр Мальцев
Александр Мальцев
Здравствуйте! Простую голосовалку можно реализовать и без движка. Но всё равно потребуется написать серверный скрипт и выбрать хранилище, в котором сохранять данные голосования (как минимум текстовый файл).
Андрей
Андрей
Приветствую Александр. Я как раз и думал о простом текстовом файле для сохранения данных голосования. Подскажите, по скрипту есть какие-то шаблоны? Где можно узнать поподробнее?