ТаблицейБлоками.

Приложение Д: PHP скрипт голосования

Последняя модификация: 10.08.2014 г

Страница загружена с адреса: http://webdesign.site3k.ru/conjuncture/append/d/golos.html

Моя студия веб-дизайна

Создание на сайте голосования

  1. Содержимое файла form.php
  2. Файл img.php

Устроить на сайте голосование с помощью PHP-скрипта – проще простого. Приведу пример, совсем не простого голосования в котором запрашиваются не просто мнение по какому-то вопросу, а мнение сразу по ряду вопросов. Используя данный пример, легко, как усложнить, так и упростить голосование, на ваше усмотрение.

Содержимое файла form.php

<html><!-- Обычное начало страницы -->
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<META name="keywords" content="">
<META name="description" content="">
<META name="Author" content="Красносельский К. К.">
</head>
<BODY TEXT=Black>
<h1>Голосование</h1>
<center>

<form name="frm" action=<?php echo $_SERVER["SCRIPT_NAME"];?>><!-- Начинается форма. Адрес action пусть даст сам сервер. Используется метод GET, файл может иметь любое расширение -->

<table cellspacing=0 cellpadding=0 border=0>

<tr><td colspan=2 align=center><B>Что вас интересовало:</B></td></tr>
<tr><td><input type=radio name="them" value=1>Компьютер (<?php echo $total[1][1];?>):
<!-- из массива будет получено количество голосов --></td>
<td><img src="img.php?<?php echo round($total[1][1]/$golosov[1]*100,2);?>">
<!-- На основании этой формулы будет получен рисунок для графического отображения результатов --></td></tr>
<tr><td><input type=radio name="them" value=2>Программы (<?php echo $total[1][2];?>):</td><td><img src="img.php?<?php echo round($total[1][2]/$golosov[1]*100,2);?>"></td></tr>
<tr><td><input type=radio name="them" value=3>Веб-дизайн (<?php echo $total[1][3];?>):</td><td><img src="img.php?<?php echo round($total[1][3]/$golosov[1]*100,2);?>"></td></tr>
<tr><td><input type=radio name="them" value=4>Гуманитарные науки (<?php echo $total[1][4];?>):</td><td><img src="img.php?<?php echo round($total[1][4]/$golosov[1]*100,2);?>"></td></tr>
<tr><td><input type=radio name="them" value=5 CHECKED>Другое (<?php echo $total[1][5];?>):</td><td><img src="img.php?<?php echo round($total[1][5]/$golosov[1]*100,2);?>"></td></tr>

<tr><td colspan=2 align=center><B>По указанной теме вы хотели найти:</B></td></tr>
<tr><td><input type=radio name="tipe" value=1>Документацию (<?php echo $total[2][1];?>):</td><td><img src="img.php?<?php echo round($total[2][1]/$golosov[2]*100,2);?>"></td></tr>
<tr><td><input type=radio name="tipe" value=2>Справочники (<?php echo $total[2][2];?>):</td><td><img src="img.php?<?php echo round($total[2][2]/$golosov[2]*100,2);?>"></td></tr>
<tr><td><input type=radio name="tipe" value=3>Статьи (<?php echo $total[2][3];?>):</td><td><img src="img.php?<?php echo round($total[2][3]/$golosov[2]*100,2);?>"></td></tr>
<tr><td><input type=radio name="tipe" value=4 CHECKED>Другое (<?php echo $total[2][4];?>):</td><td><img src="img.php?<?php echo round($total[2][4]/$golosov[2]*100,2);?>"></td></tr>

<tr><td colspan=2 align=center><B>Насколоько вы остались довольны:</B></td></tr>
<!-- Этот вопрос не имеет предустановленного значения (значения по умолчанию) и будет использоватся для контроля: голослвал ли посетитель, или просто нажал на кнопку, не задумываясь -->
<tr><td><input type=radio name="result" value=1>Очень (<?php echo $total[3][1];?>):</td><td><img src="img.php?<?php echo round($total[3][1]/$golosov[3]*100,2);?>"></td></tr>
<tr><td><input type=radio name="result" value=2>Вполне (<?php echo $total[3][2];?>):</td><td><img src="img.php?<?php echo round($total[3][2]/$golosov[3]*100,2);?>"></td></tr>
<tr><td><input type=radio name="result" value=3>Почти (<?php echo $total[3][3];?>):</td><td><img src="img.php?<?php echo round($total[3][3]/$golosov[3]*100,2);?>"></td></tr>
<tr><td><input type=radio name="result" value=4>Не очень (<?php echo $total[3][4];?>):</td><td><img src="img.php?<?php echo round($total[3][4]/$golosov[3]*100,2);?>"></td></tr>
<tr><td><input type=radio name="result" value=5>Не доволен (<?php echo $total[3][5];?>):</td><td><img src="img.php?<?php echo round($total[3][5]/$golosov[3]*100,2);?>"></td></tr>

<tr><td colspan=2 align=center><B>Как вы попали на сайт:</B></td></tr>
<tr><td><input type=radio name="link" value=1>Перешел с поисковика (<?php echo $total[4][1];?>):</td><td><img src="img.php?<?php echo round($total[4][1]/$golosov[4]*100,2);?>"></td></tr>
<tr><td><input type=radio name="link" value=2>Перешел с каталога сайтов (<?php echo $total[4][2];?>):</td><td><img src="img.php?<?php echo round($total[4][2]/$golosov[4]*100,2);?>"></td></tr>
<tr><td><input type=radio name="link" value=3>Перешел по баннеру (<?php echo $total[4][3];?>):</td><td><img src="img.php?<?php echo round($total[4][3]/$golosov[4]*100,2);?>"></td></tr>
<tr><td><input type=radio name="link" value=4>По ссылке с другого сайта (<?php echo $total[4][4];?>):</td><td><img src="img.php?<?php echo round($total[4][4]/$golosov[4]*100,2);?>"></td></tr>
<tr><td><input type=radio name="link" value=5>Рекомендовали друзья (<?php echo $total[4][5];?>):</td><td><img src="img.php?<?php echo round($total[4][5]/$golosov[4]*100,2);?>"></td></tr>
<tr><td><input type=radio name="link" value=6>Давний посетитель (<?php echo $total[4][6];?>):</td><td><img src="img.php?<?php echo round($total[4][6]/$golosov[4]*100,2);?>"></td></tr>
<tr><td><input type=radio name="link" value=7 CHECKED>Другое (<?php echo $total[4][7];?>):</td><td><img src="img.php?<?php echo round($total[4][7]/$golosov[4]*100,2);?>"></td></tr>

<tr><td colspan=2 align=center><B>Всего проголосовало: </B><?php echo $golosov[1].$WriteText;?></td></tr>

</table>
<input type=submit name=golos value="Голосовать">
</form>

</center>
</body>
</html>

 

Приведенный код – только внешний вид страницы. Теперь необходимо снадбить его скриптами.

Начальные установки скрипта

<?php 

// Первый запуск скрипта, инициализация переменных
$total = array( // Создадим двухмерный массив для данных ключи которого, для удобства, начинаются с единицы
    1   => array(1 => 0,0,0,0,0),    //"them" элементы начинаются с индекса 1
    2   => array(1 => 0,0,0,0),      //"tipe"  хранятся знечения tipe (и т. д.)
    3   => array(1 => 0,0,0,0,0),    //"result"
    4   => array(1 => 0,0,0,0,0,0,0) //"link"
);
$file_name=".data.txt"; // Имя файла начинается с точки, поэтому он недоступен для постороних

В начале скрипта создается массив из которого будут браться значения для отображения в форме (элементы вроде <?php echo $total[1][1];?>). Создание массива необходимо, чтобы при первом запуске скрипта или ошибке доступа к файлу, хранящему статистику, на страницу не выдавалось сообщение о неопределенной переменной. В дальнейшем, массив будет браться из файла и переопределять пустые значения, заданные здесь.

Применение многомерного массива в данной ситуации является наиболее эфективным и компактным решением. Для языков, не поддержывающих многомерные массивы потребовались бы очереди в памяти или непосредственная запись в базу данных. В худшем случае, пришлось бы использовать множество переменных. Но каждый из этих вариантов все более и более громоздки и медлительны (можете попробовать идти иным путем).

Переменная «$file_name» определяется здесь, чтобы не определять ее дважды там, где она будет использоваться.

Проверка пользовательского ввода и сохранение рузультатов

if (@$golos){
   if (@$them and @$tipe and @$result and @$link) {// проверка наличия всех полей
     // Следующая строка - проверка типа данных, которые могут быть неправильными, если отправлены в обход формы (JavaScript будет бессилен)
     if (is_numeric($them) and is_numeric($tipe) and is_numeric($result) and is_numeric($link)) {
    // Дальше - проверка диапазона (JavaScript будет бессилен)
    if (ereg("([1-5]{1})",$them) and ereg("([1-4]{1})",$tipe) and ereg("([1-5]{1})",$result) and ereg("([1-7]{1})",$link)) {

        // ЗАПИСЬ ДАННЫХ-----------------------------------------
        $readable=is_readable($file_name);// определить доступен ли файл на чтение
        @$file=fopen($file_name,"a+"); // открыть файл (создав, если его нет)
        if (@$file) {// если успешно открыт
        flock($file,LOCK_EX); // ждем , пока не заблокируем файл
        if ($readable){ // если файл существовал до момента открытия/создания
           $total=unserialize(fread($file, filesize($file_name)));
        }// если файл пустой (свежесозданный) унсериализировать нельзя - будет ошибка
        $total[1][$them] +=1;
        $total[2][$tipe] +=1;
        $total[3][$result] +=1;
        $total[4][$link] +=1;
        // Здесь мы учитываем номер ответа, который пришел к нам из формы,
        // увеличив соответствующее значение в массиве
        ftruncate($file,0); // очищаем все содержимое файла, независимо от того, был он или не был
        fwrite($file, serialize($total)); // Запись обновленных данных в файл
        fflush($file); // сбрасываем все изменения на диск
        flock($file,LOCK_UN); // разблокируем файл
        fclose($file);
        Header("Location: http://".$_SERVER["SERVER_NAME"]. $_SERVER["SCRIPT_NAME"]. "?return=1"); // мнение учтено, перегружаем страницу
        exit();
        }else{
            $return=2; // Ошибка открытия файла, можно отправить отчет администратору   
        }
        // -----------------------------------------
    }else{
        $return=3; // неправильный диапазон
    }
     }else{
    $return=4; // Неправильный тип
     }
   }else{
     $return=5; // не все опции
   }
}

Проверка типа данных в данном случае не имеет большого значения. Главное – проверить попадание в диапазон (попробуйте на своей копии убрать проверку диапазона и в одну из переменных занести число вне его). Если значения не подходят по типу, то и в диапазон они не попадут, но, отдельная проверка на тип, позволяет сделать более точное сообщение об ошибке.

Дальше, мы открываем файл, блокируем, считываем, одним оператором, благодаря функции unserialize, восстанавливая сохраненный в файле массив.

Далее, используем тот факт, что переменные $them и ей подобные, поступая из формы (и предварительно проверянные), содержат номера выбранных при голосовании элементов. Таким образом, конструкция типа $total[1][$them] +=1, увеличивает значение именно той ячейки первого подмассива, на которую указывает значение переменной $them. Например:

  1. Компьютер
  2. Программы
  3. ВЕБ-дизайн
  4. Гуманитарные науки
  5. Другое

Аналогично с другими подмассивами. Без использования массивов задача значительно усложнилась бы.

Далее, мы очищаем файл, с помощью функции serialize преобразовываем массив в формат, пригодный для хранения в текстовом файле, даем команду записи, сбрасываем буферы, разблокируем и закрываем файл. Закончив запись, заставляем браузер заново считать скрипт, добавив к адресу параметр return=1, который будет означать что, данные успешно всесены.

В случае каких-либо неудачь, переадресации браузера не потребуется. Достаточно в переменных, одноименых параметру, передаваемому в адресе в случае удачи (return), дать определенные значения, а позже проанализировать их.

Чтение данных из базы

Эта часть скрипта должна запускаться, если файл данных еще не открывался, чтоб не читать его дважды. Такое, обычно происходит при простом открытии страницы с формой.

if (!@$file){ // Если файл еще не открывался
   // ЧТЕНИЕ ДАННЫХ----------------------------------------
   @$file=fopen($file_name,"r"); // открыть файл
   if (@$file) {// если успешно открыт
        $total=unserialize(fread($file, filesize($file_name)));
   }
   @fclose($file); // закрыть
  // @ в $total и других, стоит для первого запуска, когда файла еще нет
 // ----------------------------------------
}

Практически, эта часть упрощенно повторяет ту, которая отвечала за чтение и запись.

Предварительная обрабатка данных для отображения в браузере

 // ОБРАБОТКА ПРОЧИТАННЫХ ДАННЫХ----------------------------------------
   for($i=1;$i <= count($total); $i++) {
    $golosov["$i"]=array_sum($total["$i"]); // подсчитаем общее количество голосов по каждой строке
    if ($golosov["$i"] == 0) {$golosov["$i"]=1;} // Для избежания ошибки деления на ноль когда еще никто не голосовал
    // (правда счетчик покажет, что голосовал 1 человек, но это не важно - сгрузив скрипт на сайт, мы проголосуем разок, для теста, и дальше все будет правильно)
   }
   if (@$golosov[1]);// @ стоит для первого запуска
   {
    if (substr($golosov[1],strlen($golosov[1])-2,1)==1) // 10 -19, 110 - 119, и т. д.
    {
        $WriteText=' человек.';
    } elseif (substr($golosov[1],strlen($golosov[1])-1,1) > 1 && substr($golosov[1],strlen($golosov[1])-1,1) < 5) // заканчивается на 2 или 3, или 4
    {
        $WriteText=' человека.';
    } else {
        $WriteText=' человек.'; // все остальные
    }
   }
 // ----------------------------------------
?>

На этом основные скрипты завершаются. Теперь мы знаем сколько человек всего проголосовало (это значение содержится в каждом элементе массива $golosov, что, при желании, можно использовать для проверки: значения должны быть одинаковыми). И имеем нормальные окончания для вывода статистики.

Все эти фрагменты скрипта необходимо поместить перед началом страницы (до тега <HTML>).

Но это еще не все: перед началом формы, следует поместить код:

<?php 
   switch (@$return) {
       case 1:
       echo "<h2><font color=#215582>Спасибо, Ваше мнение учтено!</font></h2>";
           break;
       case 2:
       echo "<h2><font color=Maroon>Извините, нам не удалось произвести запись в базу. Попробуйте позже.</font></h2>";
           break;
       case 3:
       echo "<h2><font color=red>В одной из переменных неправильный диапазон. Вы явно пытаетесь голосовать минуя форму!</font></h2>";
           break;
       case 4:
       echo "<h2><font color=red>В одной из переменных неправильный тип данных. Вы явно пытаетесь голосовать минуя форму!</font></h2>";
           break;
       case 5:
       echo "<h2><font color=red>Вы отметили не все опции!</font></h2>";
           break;
       default:
       echo "<h2>Ваше мнение о сайте:</h2>";
   }
?>

Который, исходя из значений переменной return, будет выводить либо сообщение об успешности голосования, либо сообщение о проблеме, либо обычную строку «Ваше мнение о сайте».

Но… Самое интересное, только начинается. Страница нуждается в графическом отображении резальтатов голосования. Это позволит сделать следующий скрипт (его имя должно соответствовать указанному в атрибутах src, используемых на странице расунков – img.php).

Файл img.php

Это довольно просотй файл

 

Если не вашем сервере не поддерживается Gif-формат, замените в нем все «Gif» на «PNG» или «JPG». Не смотря на свою простоту, файл оказывается очень полезным и может применятся не только в процедуре голосования. Параметры, которые ему передаются (вроде round($total[3][5]/$golosov[3]*100,2)) определяют процент людей, давших определенный ответ по теме и, используются скриптом, для задания размеров и вывода текста.

Сохраните файлы img.php и form.php, и наслаждайтесь собственным голосованием.

После отладки серверного скрипта, полезно добавить контроль данных на стороне клиента, для чего добавить в заголовочную часть страницы такой скрипт:

<SCRIPT LANGUAGE="JavaScript"><!--
function test(){
   for (i=0, testvar=false; i < document.frm.result.length; i++){
      if (document.frm.result[i].checked){
         testvar=true;
         break;
      }
   }
   if (testvar==false){alert('Вы отметили не все опции!'); return false;}
}
//--></SCRIPT>

И реакцию на событие onsubmit в форму:

<form name="frm" action=<?php echo $_SERVER["SCRIPT_NAME"];?> onsubmit="return test()">

Чтобы еще до отправки формы на сервер, проверить, все ли переключатели установлены. Пробежавшись по всем радиокнопкам с именем «result», данный скрипт проверит, есть ли среди них отмеченная и, если нет, не позволит отправить форму. Это уменьшит не только утомляемость посетителя, но и нагрузку на сервер и линию.

Увидеть данный скрипт голосования на PHP в действии можно на  странице статистики.

 

Комментарии к странице (всего 9)

 

 

 


На главную страницу сайта