Здравствуйте. Предлагаю Вашему вниманию инструкцию по созданию системы голосования на сайте.
Итак, давайте рассмотрим, что же представляет из себя система голосования на сайте.
Пользователь видит на странице форму, в которой присутствуют заголовок голования, варианты ответов, из которых можно выбрать один, тот, за который пользователь хочет проголосовать.
После выбора пользователь нажимает кнопку "проголосовать" и система засчитывает его голос в пользу того или иного варианта ответа.
"Снаружи" вроде всё просто: обычная форма, обычная кнопка, обычные radio-кнопки. Но давайте заглянем "за кулисы" работы скрипта голосования. Там нашему взору откроется более интересная картина.

Что же представляет из себя система голосования изнутри?
Как можно запоминать выбор пользователя и не давать ему голосовать повторно?
Как создавать вопросы и варианты ответов?
На эти вопросы мы сейчас попробуем получить развёрнутый ответ. Нам нужно где-то хранить вопросы и варианты ответов. Для этого нам потребуется создать базу данных MySQL и пару таблиц в ней.
Давайте создадим такие таблицы:
voting - таблица, в которой будут храниться вопросы и варианты ответов.
voted - таблица, в которой будут храниться выбранные варианты ответов и IP адреса проголосовавших.

В таблице voting нам нужно создать три поля:
1. id - тип INTEGER, AUTOINCREMENT.
В поле будет содержаться идентификатор вопросов и ответов.
2. parent_id - тип INTEGER.
В поле будет содержаться идентификатор родительской записи (т.е. по отношению к ответам, родительской записью будет вопрос).
3. title - тип VARCHAR.
В поле будет содержаться текст вопросов и ответов.

Как видите, мы будем хранить вопросы и ответы в одной таблице. Поскольку нам в данном случае нужна связь один-ко-многим и поля, необходимые для хранения вопросов и ответов одинаковые,- это очень удобный вариант.
Тут плюс в том, что не нужно создавать отдельные таблицы для вопросов и ответов, и запросов в БД нужно будет делать меньше.

В таблице voted нам нужно создать два поля:
1. answer_id - тип INTEGER.
В поле будет содержаться идентификатор выбранного пользователем ответа (т.е. ответа, за который он проголосовал).
2. ip - тип VARCHAR. UNIQUE.
В поле будет содержаться IP-адрес пользователя, который проголосовал. В данном поле будут только уникальные значения IP.

На этом моменте остановимся поподробнее. Почему мы запоминаем IP пользователя? Ведь IP бывают динамическими, скажете Вы. И пользователь, сменив IP, сможет проголосовать несколько раз. Я с Вами полностью согласен, но ещё не придумано 100% надёжного варианта запонимания неавторизованного пользователя.
Почему я упомянул авторизацию: если мы хотим, чтобы пользователь гарантированно не смог проголосовать несколько раз, нам нужно сделать систему авторизации и заместо IP пользователя использовать для учёта его голоса идентификатор его аккаунта.
И сделать открытым голосование только для авторизованных пользователей. Но создание голосования для авторизованных не входит в планы данной статьи, поэтому для учёта голоса будем запоминать IP.

Итак, мы создали таблицы, теперь давайте перейдём непосредственно к реализации php-скрипта системы голосования. Давайте разберём вот такой класс:

db = new PDO($dsn, "root", ""); # Устанавливаем ID голосования $this->id = $id; } /** * Для выборки из базы голосования по установленному ID * * @return заполняет массив $this->result данными */ private function selectVoting(){ # SQL-запрос для выборки опроса $stmt = $this->db->prepare("SELECT id, title, 0 as voted FROM `$this->tbl_voting` WHERE id=:id AND parent_id=0 UNION SELECT o.id, o.title, COUNT(v.ip) FROM `$this->tbl_voting` o LEFT JOIN `$this->tbl_voted` v ON v.answer_id = o.id WHERE parent_id=:id GROUP BY o.id"); # Выполняем запрос $stmt->execute(array(":id" => $this->id)); # Получаем ассоциативный массив $this->result["voting"] = $stmt->fetchAll(PDO::FETCH_ASSOC); # Если данных нет if(!$this->result) # Бросаем исключение throw new Exception("Голосования с ID ". $this->id ." нет"); } /** * Для проверки, голосовал ли уже пользователь * * @return */ private function checkAlreadyVoted(){ # SQL-запрос для выборки опроса $stmt = $this->db->prepare("SELECT COUNT(*) FROM `$this->tbl_voted` WHERE ip=:ip AND answer_id IN(SELECT id FROM `$this->tbl_voting` WHERE parent_id=$this->id)"); # Выполняем запрос $stmt->execute(array(":ip" => $this->getIP())); # Записываем полученные данные в конечный массив $this->result["already_voted"] = (bool) $stmt->fetch(PDO::FETCH_COLUMN); } /** * Для разбора массива, установленного в select() * * @return заполняет массив готовыми для шаблона данными */ private function prepare(){ # Получаем из массива первый элемент (вопрос) $ask = array_shift($this->result["voting"]); # Записываем готовые данные в итоговый массив $this->result = array("title" => $ask["title"], "options" => $this->result["voting"], "already_voted" => $this->result["already_voted"]); } /** * Для получения IP-адреса * * @return IP-адрес пользователя */ private function getIP(){ return getenv("REMOTE_ADDR"); } /** * Для получения массива с информацией о голосовании * @param integer $id - идентификатор голосования, * которое нужно вывести * * @return */ public function get(){ # Вызываем метод выборки данных из БД $this->selectVoting(); # Вызываем метод проверки, голосовал ли пользователь $this->checkAlreadyVoted(); # Вызываем метод обработки полученных данных $this->prepare(); # Возвращаем массив данных return $this->result; } /** * Для добавления голоса к опросу * * @return */ public function add($id){ # Подготавливаем запрос для добавления голоса $stmt = $this->db->prepare("INSERT IGNORE INTO `$this->tbl_voted` VALUES ((SELECT id FROM `$this->tbl_voting` WHERE id=:id), :ip)"); # Выполняем запрос $stmt->execute(array(":id" => $id, ":ip" => $this->getIP())); } }


Класс довольно неплохо прокомментирован, поэтому разберём только самые интересные методы данного класса. Для начала нам нужно настроить соединение с нашей базой банных. Для этого в конструкторе нужно указать хост, имя базы данных, имя пользователя и пароль.
Как видите, в мы используем для работы с базой данных расширение PDO. С этим расширением очень удобно работать, и при правильном составлении запросов ещё и безопасно, никакие SQL-инъекции не будут страшны.
Если у Вас возникли затруднения в настройке соединения с базой данных, обратитесь к документации PDO:

Теперь давайте разберём метод выборки вопроса и соответствующих ему ответов:

private function selectVoting(){ # SQL-запрос для выборки опроса $stmt = $this->db->prepare("SELECT id, title, 0 as voted FROM `$this->tbl_voting` WHERE id=:id AND parent_id=0 UNION SELECT o.id, o.title, COUNT(v.ip) FROM `$this->tbl_voting` o LEFT JOIN `$this->tbl_voted` v ON v.answer_id = o.id WHERE parent_id=:id GROUP BY o.id"); # Выполняем запрос $stmt->execute(array(":id" => $this->id)); # Получаем ассоциативный массив $this->result["voting"] = $stmt->fetchAll(PDO::FETCH_ASSOC); # Если данных нет if(!$this->result) # Бросаем исключение throw new Exception("Голосования с ID ". $this->id ." нет"); }


Как видите, здесь мы используем prepared statement (подготовленные запросы) PDO. В самом запросе мы указываем якорь ":id", а затем в методе "execute" указываем, каким значением заменить данный якорь.
В данном SQL запросе мы используем объединение результатов запросов помощью UNION. Первым SELEСЕ"ом мы выбираем необходмый вопрос (идентификатор которого содержится в свойстве "id" данного класса), а
вторым выбираем принадлежащие данному вопросу варианты ответов и количество голосов за определённыый вопрос (для вывода статистики).
В результате данного запроса мы получаем массив, первым элементом которого является вопрос, а остальными элементами - варианты ответа на вопрос. Теперь нам нужно отделить вопрос от ответов. Для этого мы используем метод "prepare":

/** * Для разбора массива, установленного в select() * * @return заполняет массив готовыми для шаблона данными */ private function prepare(){ # Получаем из массива первый элемент (вопрос) $ask = array_shift($this->result["voting"]); # Записываем готовые данные в итоговый массив $this->result = array("title" => $ask["title"], "options" => $this->result["voting"], "already_voted" => $this->result["already_voted"]); }


C помощью array_shift мы вырезаем вопрос из массива и вставляем текст вопроса в результирующий массив (который передадим уже на вывод). Как видите, здесь встречается такой элемент, как "already_voted".
В нём мы содержим информацию, голосовал ли пользователь ранее, т.е. содержится ли IP пользователя в таблице "voted". Проверка на наличие IP в таблице производится в методе "checkAlreadyVoted".

Ну что, с данным классом мы разобрались, теперь сохраните его в файл (назовите его "voting.class.php") и скопируйте к себе на сервер. Далее давайте разберём, как мы будем выводить голосование на экран.
Сначала нам нужно подключить вышеописанный класс на страницу, где будем выводить голосование. Я не знаю, каким образом работает Ваша CMS, поэтому давайте подключим, используя обычный "require":

require("путь к файлу/voting.class.php");


Отлично, класс подключён. Можно с ним работать. Но у нас пока нет ни одного голосования,- давайте создадим его. Для этого нужно зайти в phpMyAdmin, выбрать таблицу "voting" и вставить в неё вопросы и ответы.
Допустим, мы хотим узнать от пользователей, как они относятся к нашему сайту. Для этого в поле "title" вставим такой вопрос: "Как Вам наш сайт?". В поле "parent_id" нужно вставить "0", так как это вопрос и он не является дочерней записью другого вопроса.
После сохранения мы видим, что у нас появилась новая запись в таблице. Теперь мы знаем её идентификатор (находится в поле "id"), это и есть идентификатор вопроса, по этому идентификатору мы привяжем к вопросу варианты ответов на него.
Теперь создадим варианты ответов, для этого в поле "title", например впишем "Отлично". Эта запись и будет одним из вариантов ответа. В поле parent_id нам нужно указать идентификатор вопроса, к которому принадлежит данный ответ.
Таким образом создайте необходимое количество вариантов ответов, не забывая в поле parent_id указывать идентификатор вопроса.

Что ж, мы успешно создали вопрос и варианты ответов на него в базе данных. Теперь перейдём к выводу голосования на страницу.
Для того, чтобы вывести необходимое голосование, нам нужно создать экземпляр объекта класса, который мы подключили на страницу ранее:


В коде выше мы видим, что у нас создаётся объект класса, в качестве аргумента конструктору которого передаётся ID вопроса. Как видите, нам не нужно перечислять ID всех записей в БД, принадлежащих данному голосованию. Достаточно указать лишь ID вопроса, а дочерние записи (т.е. у которых в поле "parent_id" содержится ID данного вопроса)
подтянутся вместе с ним, с помощью UNUON, о котором мы говорили ранее. Сейчас мы передаём ID "1", если у Вашего вопроса идентификатор другой - передайте его, единица здесь только для примера.
Если Вы всё правильно сделали, в итоге, в переменной $data у Вас будет примерно такой массив:

array(3) { ["title"]=> string(30) "Как Вам наш сайт?" ["options"]=> array(3) { => array(3) { ["id"]=> string(1) "2" ["title"]=> string(27) "Первый вариант ответа" ["voted"]=> string(1) "0" } => array(3) { ["id"]=> string(1) "3" ["title"]=> string(13) "Второй вариант ответа" ["voted"]=> string(1) "0" } => array(3) { ["id"]=> string(1) "4" ["title"]=> string(27) "Третий вариант ответа" ["voted"]=> string(1) "0" } } ["already_voted"]=> bool(false) }


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

- голосов



Как мы видим, в коде проводится проверка, голосовали ли пользователь ранее:


Если пользователь уже голосовал (т.е. его IP есть в таблице voted ), то ему выводится на экран статистика голосов, т.е. ответы и количество пользователей, проголосовавших за тот или иной ответ. Тут Вы можете подключить фантазию и доработать скрипт, например, сделав вывод статистики в виде графика.
Если же пользователь не принимал участие в данном голосовании, то ему выводится форма, в которой он может выбрать необходимый вариант ответа и проголосовать за него.
В цикле мы проходим по всем вариантам ответов и выводим их на экран. В качестве значения в поля "radio" вставляются их идентификаторы:

"/>


Допустим, пользователь выбрал необходимый ответ и нажал "Голосовать". После этого он перейдёт к скрипту "voted.php", как мы видим в коде, "action" формы ведёт именно на этот скрипт:


Теперь создадим файл "vote.php" и напишем в нём такой код:

add($id); # Перенаправляем назад header("Location: " . getenv("HTTP_REFERER")); } } catch(Exception $e){ # Выводим сообщение echo $e->getMessage(); }


Как видите, в нём мы тоже подключаем класс голосования. Затем проводится проверка, нажата ли кнопка "Голосовать". Если нажата - получаем ID ответа, за который голосует пользователь.
Так же создаётся экземпляр класса голосования, только теперь мы не передаём ID вопроса в конструктор, тут он не требуется, так как опрерируем на данном этапе только с ответом.
Затем мы вызываем метод "add", передавая в него идентификатор вопроса:

$voting->add($id);


В методе "add" мы используем INSERT IGNORE для того, чтобы IP пользователя повторно не записывался в таблицу, ведь лишние записи нам ни к чему.
После того, как голос пользователя учтён или проигнорирован (в случае, если IP уже есть в таблице), идёт перенаправление его на предыдущую страницу:

header("Location: " . getenv("HTTP_REFERER"));


Ну вот и всё, голосование готово. Её можно ещё конечно доработать, добавив возможность создавать и удалять голосования из админки, добавив внешние ключи для таблиц, чтобы при удалении вопроса из базы удалялись и все связанные с ним вопросы и записи в таблице voted .
Но это уже на Ваше усмотрение.

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

1. Скрипт голосования на сайте удобно разместить в отдельном файле, например, votes.php. Наш скрипт должен создавать таблицу базы данных о голосах за каждый конкретный товар, таблица создаётся автоматически при первом голосовании за данный товар. Ведь не заставлять же администраторов сайта-каталога создавать таблицу вручную при внесении в каталог каждого нового товара! Таблица содержит поля, ответственные за идентификационный номер голоса, идентификационный номер товара, собственно переменной, обозначающей, что голос подан (можно придать ей значение "1", строки с этими полями затем подсчитываются при формировании рейтинга), IP пользователя (но можно и без него), ник пользователя и категорию товара.

Код PHP/MySQL

mysql_query ("CREATE TABLE IF NOT EXISTS votes_$cid (

vid int(10) NOT NULL auto_increment,

id int(10) NOT NULL,

pluss int(10) NOT NULL,

ip_addr char(50) NOT NULL,

nick varchar(255) NOT NULL,

dat_lim date NOT NULL,

cid int(10) NOT NULL,

PRIMARY KEY(vid)

) ENGINE=MyISAM DEFAULT CHARSET=utf8") Or die (mysql_error ());

Показанная в коде выше конструкция автоматического создания таблицы является предметом вопроса в .

Пусть на сайте голосовать имеют возможность лишь зарегистрированные пользователи, можно установить ограничение голосования по дате, установить суточный лимит голосования за тот или иной товар (это всё на случаи, если есть подозрения в "накрутке голосов"), а также открывать голосование лишь спустя некоторое время после появления товара в каталоге, а также устанавливать дату окончания голосования, если этого требует конкретная бизнес-логика.

2. В нашем скрипте должна происходить проверка, отправлены ли данные из формы, то есть, нажал ли посетитель каталога кнопку "голосовать" (за это отвечает переменная $_POST["sended"] со значением "yes"). Далее - проверка, является ли проголосовавший зарегистрированным пользователем ($rights>0). Если есть необходимость завершить голосование за тот или иной товар к определённой дате - проверка, не завершено ли голосование ($end_dat

Код PHP

if ($_POST["sended"]=="yes")

if ($rights>0)

if ($row01==0)

$dat=date ("Y-m-d H:i:s");

if ($end_dat

elseif ($dat

3. Если в соответствии с датой голосовать можно, выполняется блок голосования. Однако в его начале происходит проверка, не исчерпан ли суточный лимит голосования за данный товар, а также проверка на случай, если голосование ещё не открыто. Если всё в порядке и голосовать можно, данные заносятся в базу, в ту её таблицу, которая содержит данные о голосовании за данный товар (таблица votes_$cid). Далее путём нового запроса к этой же таблице подсчитывается число голосов (строк) за товар с данным id. Затем в таблицу с данными обо всех товарах (goods) соответственно id товара записывается обновлённое число строк, каждая из которых означает один голос за данный товар.

Код PHP

if ($end_dat

elseif ($dat

if ($row11

if ($v_cl==1)

elseif ($v_cl==0)

4. А ниже показано, что предусматривает программа в случае отрицательных ответов на обозначенные выше вопросы.

Код PHP

else

else

else

else

echo "It`snt OK";

5. И, наконец полный код блока, реализующего голосование. Нужно только перед показанным кодом сделать проверку (if (isset ...)), существуют ли значения переменных, переданных из формы для голосования в наш скрипт. А в самом верху разместить запрос к базе на создание новой таблицы (самый первый фрагмент кода)

Код PHP

$result01=mysql_query ("SELECT * FROM votes_$cid WHERE nick="$nick" AND id="$id"") or die (mysql_error ());

$row01 = mysql_num_rows ($result01);

$resultT=mysql_query ("select voting_closed,end_ FROM categories WHERE cid="$cid"") or die (mysql_error ());

$myrowT=mysql_fetch_array ($resultT);

$end_dat = $myrowT;

$v_cl = $myrowT;

$dat_new=date ("Y-m-d");

$resultL1=mysql_query ("select * FROM votes_$cid WHERE dat_lim="$dat_new" AND id="$id"") or die (mysql_error ());

$row11 = mysql_num_rows ($resultL1);

if ($_POST["sended"]=="yes")

if ($rights>0)

if ($row01==0)

$dat=date ("Y-m-d H:i:s");

if ($end_dat

elseif ($dat

if ($row11

if ($v_cl==1)

elseif ($v_cl==0)

$result1=mysql_query ("INSERT INTO votes_$cid

(id,ip_addr,nick,pluss,dat_lim,cid)

VALUES ("$id","$ip_addr","$nick","$pluss","$dat_new","$cid")");

$result2=mysql_query ("SELECT * FROM votes_$cid WHERE id="$id"") or die (mysql_error ());

$row2=mysql_num_rows ($result2);

$result3=mysql_query ("UPDATE goods SET votes="$row2" WHERE id="$id"");

else

else

else

else

echo "It`snt OK";

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

Кнопки download в количестве 27 для оформления вашего сайта. Формат – png и psd. Скачать с Яндекс Диска .

Пример создания простой кнопки download в фотошопе. Создание такой кнопки не отличается от создания любой другой. И как варианты вы можете использовать другие уроки фотошопа по кнопкам нашего сайта – , . Результат:

Создайте новый документ в фотошопе с размерами 200 на 80 пикселей и прозрачным фоном.

Возьмите инструмент «Прямоугольник с закругленными краями”. В настройках инструмента активируйте “стиль-заливку” и радиус = 10, цвет фигуры – любой.

Зайдите в стили слоя фигуры и активируйте “Наложение градиента”. В редакторе градиента проставьте цвета: #2c0591, #6586e7, #6586e7 и #ffffff.

Градиент – линейный, угол – “-90”, режим нормальный, непрозрачность – 100%.

Теперь активируйте обводку в стилях слоя. Настройки обводки: размер – 6, положение – снаружи, режим – нормальный, непрозрачность – 100%, тип обводки – градиент, цвета градиента – #000000, #000000, #eeab35, #eeab35, #000000, #000000, стиль – разбивка фигуры, угол 90. Скриншоты ниже:

Получили:

Теперь берем иснтрумент “Овальная область” любого цвета и рисуем круг на кнопке слева. Для того, чтобы получился идеальный круг зажимаем клавишу Shift.

Теперь переходим в стили слоя фигуры окружности и применяем следующие параметры:

Результат:

Теперь берем фигуру стрелки , ее вы найдете в стандартном наборе Стрелки:

Нарисуйте фигуру так, чтобы она по размеру не выходила за пределы круга. Цвет фигуры – белый. Дублируйте слой со стрелкой (cTRL +J). Переместите одну из стрелок так, чтобы одна находилась под другой:

Выделите 2 слоя со стрелками (кликните поочередно по кадждому из слоев с зажатой клавишей Ctrl). После чего – клик правой кнопкой мыши и выберите пункт “Образовать смарт-объект”.

Зайдите в стили смарт объекта (двойной клик по слою смарт-объекта) и примените параметры наложения – тиснение и контур. Настройки тиснения:

Настройки Контура оставьте без изменений.

Нам остался последний штрих – надпись Download. Инструмент Текст, шрифт по жирнее (в примере – шрифт TR). Цвет вводимого текста – #f5e0ad. Стиль слоя – активируем Обводку и выставляем значения: размер – 4, положение – снаружи, режим – нормальный, непрозрачность – 100, тип – градиент (черный по краям, прозрачный в средней части), угол – 0.