Войти Регистрация

PHP: скрипт оценки на PHP + jQuery + AJAX


скрипт оценки на phpВ этой статье вы узнаете как написать скрипт системы оценок на PHP. Также для реализации полноценной и красивой системы оценок, мы будем использовать AJAX и jQuery. Рейтинг голосов будет записан в режиме реального времени, без обновления страницы с помощью AJAX. Для работы с AJAX уже есть все необходимое у фреймворке jQuery. Однако, если желаете узнать больше, читайте статью взаимодействие ajax с php.  Также, будем использовать возможности PHP таким образом, чтобы обойтись без использования базы данных. Хотя если вам удобнее использовать базу данных для хранения рейтинга вашего материала, вы с легкостью можете переписать скрипт для собственного удобства.

По просьбам пользователей, исходные файлы скрипта оценок: demo_stars.zip

Шаг 1 – Построение дизайна HTML + CSS

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

Общий вид php скрипта оценок

Давайте посмотрим на HTML и CSS кода системы оценок:

<div class='movie_choice'>  
    Rate: Raiders of the Lost Ark  
    <div id="r1" class="rate_widget">  
        <div class="star_1 ratings_stars"></div>  
        <div class="star_2 ratings_stars"></div>  
        <div class="star_3 ratings_stars"></div>  
        <div class="star_4 ratings_stars"></div>  
        <div class="star_5 ratings_stars"></div>  
        <div class="total_votes">vote data</div>  
    </div>  
</div>  
  
<div class='movie_choice'>  
    Rate: The Hunt for Red October  
    <div id="r2" class="rate_widget">  
        <div class="star_1 ratings_stars"></div>  
        <div class="star_2 ratings_stars"></div>  
        <div class="star_3 ratings_stars"></div>  
        <div class="star_4 ratings_stars"></div>  
        <div class="star_5 ratings_stars"></div>  
        <div class="total_votes">vote data</div>  
    </div>  
</div>

Следует отметить, что графики в HTML нет. Она присутствует в CSS коде. Мы используем HTML, только для примера, для создания рабочей среды, чтобы протестировать систему оценок. Давайте посмотрим CSS код:

.rate_widget {  
    border:     1px solid #CCC;  
    overflow:   visible;  
    padding:    10px;  
    position:   relative;  
    width:      180px;  
    height:     32px;  
}  
.ratings_stars {  
    background: url('star_empty.png') no-repeat;  
    float:      left;  
    height:     28px;  
    padding:    2px;  
    width:      32px;  
}  
.ratings_vote {  
    background: url('star_full.png') no-repeat;  
}  
.ratings_over {  
    background: url('star_highlight.png') no-repeat;  
}  

Этот код CSS служит для нескольких вещей:

  1. Определяет место по умолчанию для каждой пустой звезды
  2. Устанавливает классы для заполненных (активных) звезд и классы для постоянных активных звезд. Далее поймете о чем я.
  3. Определяет стиль контейнера звезд.

Вы можете воспользоваться нашими исходниками или создать собственные. Только должны присутствовать изображения трех типов: пустая оценка, выполнена, подсвечивающая.

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

.total_votes {  
    background: #eaeaea;  
    top: 58px;  
    left: 0;  
    padding: 5px;  
    position:   absolute;  
}  
.movie_choice {  
    font: 10px verdana, sans-serif;  
    margin: 0 auto 40px auto;  
    width: 180px;  
}  

Шаг 2 – Создаем интерактивность в интерфейсе

На данный момент, мы имеем просто набор звезд, которые при наведении в конкретную точку оценивания не реагируют ни на что. Это мы поправим с помощью jQuery.

Интерактивность php скрипта оценок

Нашим первым делом будет создание обработчиков событий mouseoverи mouseout. Но, нужно чтобы выделялись текущая звезда и все предыдущие звезды.

$('.ratings_stars').hover(  
    // Handles the mouseover  
    function() {  
        $(this).prevAll().andSelf().addClass('ratings_over');  
        $(this).nextAll().removeClass('ratings_vote');  
    },  
    // Handles the mouseout  
    function() {  
        $(this).prevAll().andSelf().removeClass('ratings_over');  
        set_votes($(this).parent());  
    }  
);

Пользуясь методами prevAll() и NextAll(), получаем предыдущие и последующие звезды в реальном времени при наведении мыши на них. Выше предоставленный код  добавляет и удаляет классы при наведении и отведении мыши от звезд, таким образом, подсвечивая их.

Что делает set_votes()?

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

Шаг 3 – Получение данных из сервера

Сейчас мы реализуем выделение текущего рейтинга оценок, а точнее сделаем красными звезды показывающие текущую позицию в рейтинге оценок. Чтобы это удалось нам необходимо получить данные из сервера и обработать их несколькими javascript функциями.

$('.rate_widget').each(function(i) {  
    var widget = this;  
    var out_data = {  
        widget_id : $(widget).attr('id'),  
        fetch: 1  
    };  
    $.post(  
        'ratings.php',  
        out_data,  
        function(INFO) {  
            $(widget).data( 'fsr', INFO );  
            set_votes(widget);  
        },  
        'json'  
    );  
}); 

Это javascript код, который пишется в теле документа. Он выполняется сразу: посылает запрос к серверу и получает информацию для каждого из блоков рейтинга оценок.

В начале кода мы создаем объект out_data, который содержит информацию, которую мы посылаем на сервер. Также указываем наш PHP скрипт, который будет, исполнятся при запросе получения данных из сервера. Также указываем ID конкретного контейнера оценок, который позволяет серверной стороне знать какие данные необходимо выслать. Когда выполнится ответная функция на сервере, javascript получает объект, который выглядит таким образом:

{  
    "widget_id"     : "r1",  
    "number_votes"  : 129,  
    "total_points"  : 344,  
    "dec_avg"       : 2.7,  
    "whole_avg"     : 3  
}

Если внимательно посмотрите на код, то увидите, что мы берем этот объект (он хранится в переменной INFO) и что-то делаем с ним через метод data(). Этот метод позволяет связать произвольные данные с DOM объектом. В этом случае мы храним данные в div блоке каждого контейнера рейтинга оценок. Позже мы можем получить данные к ним таким образом:

$('#one_of_your_widgets).data('fsr').widget_id; 

После получения данных с сервера, передаем их у функцию set_votes(), о которой уже упоминалось ранее. Ниже код этой функции:

function set_votes(widget) {  
  
    var avg = $(widget).data('fsr').whole_avg;  
    var votes = $(widget).data('fsr').number_votes;  
    var exact = $(widget).data('fsr').dec_avg;  
  
    $(widget).find('.star_' + avg).prevAll().andSelf().addClass('ratings_vote');  
    $(widget).find('.star_' + avg).nextAll().removeClass('ratings_vote');  
    $(widget).find('.total_votes').text( votes + ' votes recorded (' + exact + ' rating)' );  
} 

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

7 строка: avg это целое число от 1 до 5, которое используется для заполнения звезд отображающих среднестатистическую оценку.

8 строка: по синтаксису схожа с 7 строкой, только в этом случае, мы заполняем остальные звезды графика.

9 строка: Обновляет информацию в сером блоке под рейтингом оценок, показывает общее количество голосов и более точную оценку конкретного материала.

Шаг 4 – Оцениваем материал

Оценивание материалов на php

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

$('.ratings_stars').bind('click', function() {  
    var star = this;  
    var widget = $(this).parent();  
  
    var clicked_data = {  
        clicked_on : $(star).attr('class'),  
        widget_id : widget.attr('id')  
    };  
    $.post(  
        'ratings.php',  
        clicked_data,  
        function(INFO) {  
            widget.data( 'fsr', INFO );  
            set_votes(widget);  
        },  
        'json'  
    );  
});

Этот код мы начинаем писать из создания некоторых переменных, не только для чистоты кода, но в этом случае, они используются внутри .post. Также в этих переменных, указывается какая звезда и из какого блока рейтинга оценок нажата. Далее, мы определяем данные для отправки на сервер (clicked_data): определяем какой класс стиля у звезды, он содержит порядковый номер звезды и само собой оценку пользователя, также получаем ID блока рейтинга оценок.

В конце обработчика, мы отсылаем данные на сервер. Серверная сторона приложения добавляет голос (оценку), и возвращает информацию в браузер, которая имеет обновленные данные. Эти данные выводятся с помощью функции set_votes().

Шаг 5 – PHP: создаем класс системы оценок

Обмен данными скрипта с сервером

Мы создадим очень простой класс в PHP, который называется “Ratings”. Как вы уже догадались, он будет обрабатывать запросы в нашей системе скрипта оценок. Использование нашего класса будет примерно таким:

# New Object  
$rating = new ratings($_POST['widget_id']);  
  
# either return ratings, or process a vote  
isset($_POST['fetch']) ? $rating->get_ratings() : $rating->vote(); 

Далее мы создадим класс и конструктор:

class ratings {  
  
    private $data_file = './ratings.data.txt';  
    private $widget_id;  
    private $data = array();  
  
function __construct($wid) {  
  
    $this->widget_id = $wid;  
  
    $all = file_get_contents($this->data_file);  
  
    if($all) {  
        $this->data = unserialize($all);  
    }  
}

В этом небольшом куске PHP кода, очень многое происходит, а точнее:

Строка 3: Устанавливаем путь к нашему txt файлу, в котором вы хотите хранить рейтинг оценок. Как уже упоминалось, мы не будем использовать базу данных. Если вам это необходима, вы с легкостью можете переписать код.

Строка 7: Конструктор. Создаем объект и сохраняем идентификатор конкретного блока рейтинга оценок.

Строка 11: Пробуем загрузить текстовый файл. Если файла не существует, это плохо, его необходимо создать и установить права доступа к нему, чтобы PHP мог считывать и записывать в него.

Строка 14: На этом участке получаем данные из файла и с помощью unserialize() мы преобразуем сложный PHP набор в текстовое представление. Также функция serialize(), которая преобразует данные для хранения в файле. Эти функции позволяют хранить данные в текстовом файле в виде массивов.

 Шаг 6 – Создаем метод get_ratings()

Этот метод вызывается сам по себе, или от vote() метода. Он находит данные для конкретного блока рейтинга оценок по идентификатору и возвращает на запрашиваемую страницу в JSON формате.

public function get_ratings() {  
    if($this->data[$this->widget_id]) {  
        echo json_encode($this->data[$this->widget_id]);  
    }  
    else {  
        $data['widget_id'] = $this->widget_id;  
        $data['number_votes'] = 0;  
        $data['total_points'] = 0;  
        $data['dec_avg'] = 0;  
        $data['whole_avg'] = 0;  
        echo json_encode($data);  
    }  
}

Шаг 7 – Создаем vote() метод

Далее нам необходимо создать метод обработки входящих голосов. Когда метод закончит свою роботу, он вызывает get_ratings(), для отправки обновленных данных обратно в браузер.

public function vote() {  
    # Get the value of the vote  
    preg_match('/star_([1-5]{1})/', $_POST['clicked_on'], $match);  
    $vote = $match[1];

$ID = $this->widget_id;  
# Update the record if it exists  
if($this->data[$ID]) {  
    $this->data[$ID]['number_votes'] += 1;  
    $this->data[$ID]['total_points'] += $vote;  
}  
# Create a new one if it does not  
else {  
    $this->data[$ID]['number_votes'] = 1;  
    $this->data[$ID]['total_points'] = $vote;  
} 

$this->data[$ID]['dec_avg'] = round( $this->data[$ID]['total_points'] / $this->data[$ID]['number_votes'], 1 );  
    $this->data[$ID]['whole_avg'] = round( $this->data[$ID]['dec_avg'] );  
  
    file_put_contents($this->data_file, serialize($this->data));  
    $this->get_ratings();  
}

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

В заключение о скрипте оценок

Как вы понимаете, это не является 100% решением реализации скрипта оценок. Для расширения этого проекта, мы должны использовать куки, чтобы один человек, голосовал один раз. Для этого достаточно записать в куки IP адрес и при выводе блока оценок сравнивать с текущим IP. Спасибо за ваше внимание и терпение! Если у вас остались вопросы или недопонимание, обращайтесь через форму комментариев.



Дальше: Описание доменных зон


Дискуссия по теме    15 Комментариев
Добавить комментарий
Никита 27.01.2016 в 09:31
И зачем в куку еще IP пихать и потом сравнивать с текущим?! Если кука рейтинга установлена то и так понятно что человек голосовал. IP это уже другая история с защитой от накруток, и пишут его в свою базу.
Nicky 09.12.2015 в 23:45
лал, что бы работало - оберни скрипты в window.onload = function(){}
Куки 10.01.2013 в 12:23
Здравствуйте! Очень нужна запись в куки. На странице идет много фотографий, к которым прикручен этот рейтинг по ID. Но вот записать в куки хотя бы IP адрес что-то не могу сообразить как. У меня уровень в AJAX очень низкий, т.е. могу скомпилировать из чужих скриптов, но самому написать очень сложно. Если бы Вы могли помочь с этим делом, то скрипт был бы полноценным и Вы очень бы помогли. Спасибо!
hex 05.03.2012 в 10:21
ну как же его привязать к БД?
Kote 18.02.2012 в 19:41
Хороший перевод статьи! Да и сам скрипт полезный, но есть минус в нём существенный, но поправимый! Это как раз то что он не проверяет куки! Очень очень жаль. Самому конечно можно сделать но нужно повозится с ним, правда удивляюсь что написали такой простой и хороший скрипт, да и что важно без использования бд, но куки не добавили =) Скрипт полностью рабочий главное правильно указать пути к файлу обработки и к файлу бд. А css и js лучше вывести в отдельный файл и подключить их, так как скрипт может использоваться на нескольких страницах и что бы в случае чего не перебивать скрипт 15 раз. Успехов в развитии!
Дмитрий 07.02.2012 в 09:39
Во че-то зафурычило - надо било в ту же папку где все файлы этой страницы библиотеку jquery скидывать!!!
Дмитрий 07.02.2012 в 09:29
Если подключать так script src="http://code.jquery.com/jquery-latest.js" - при наведении только желтыми звездочки становятся и сё !? Короче не фурычит ваша батва !!
Дмитрий 07.02.2012 в 09:21
Nihe не работает у меня!!! Все возможные последние версии jquery подключал- только пустые звездочки на странице без изменений. Как, что, почему!!????? Пример взял из demo_stars.zip.
Тарас 22.11.2011 в 18:59
Без библиотеки jquery не обойтись, так как весь скрипт написан с использованием этой библиотеки. Но можно скачать библитеку в отдельном файле, после чего сжать js код библиотеки и подключить. Есть вариант написать скрипт оценок самому, но это лишняя головная боль и трата времени.
serg 22.11.2011 в 06:27
без подгрузки библиотеки jquery-latest.js не работает, но она огромная (более 300 Кб). Можно ли обойтись без неё или выдернуть из неё только необходимые функции?
serg 18.11.2011 в 12:17
Без этой сточки все не работает script src="http://code.jquery.com/jquery-latest.js"
Dmitry 14.11.2011 в 13:35
а как сделать механизм с кукисами, т.е. чтобы пользователь мог голосовать только один раз?
Тарас 10.10.2011 в 13:54
damirka, добавил исходники скрипта в начале статьи. Вот ссылка на демонстрацию: http://demo.jeffrey-way.com/ratingSystem/page.html
damirka 08.10.2011 в 22:04
Не работает...((( Вроде все вбил как надо...( Нет ли готовых файлов?(
Geralt 30.09.2011 в 08:22
Что такое 'fsr' ?
Добавить комментарий
Просмотров: 15267