‹
| КрасносельскийКонстантинКонстантинович |
ТаблицейБлоками.Приложение Д: PHP скрипт голосования |
Последняя модификация: 10.08.2014 г
Страница загружена с адреса: http://webdesign.site3k.ru/conjuncture/append/d/golos.html
Устроить на сайте голосование с помощью 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. Например:
Аналогично с другими подмассивами. Без использования массивов задача значительно усложнилась бы.
Далее, мы очищаем файл, с помощью функции 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).
Это довольно просотй файл
Если не вашем сервере не поддерживается 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 в действии можно на
странице статистики.
