Пишем функцию лайков для постов блога


22-10-2018
Денис Л.
Разное
175
11453
Пишем функцию лайков для постов блога

Для чего нужна функция лайков? В первую очередь, чтобы пользователи могли оценить Вашу запись, а также видеть, как её оценивают другие. Как сделать самостоятельно такой функционал - я расскажу в данном посте. Если Вам понравится данный пост - поставьте лайк! :)

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

Создаём таблицу. Назовём её likes. Если Вы используете phpMyAdmin - находясь в корне всех таблиц, ниже кнопки "Создать таблицу" вводим имя likes, количество столбцов ставим 3, нажимаем "Вперёд".

Первому столбцу вводим имя - id, тип - INT, Индекс - PRIMARY (во всплывающем окне нажимаем ВПЕРЁД), ставим галочку A_I (auto increment).

Второму столбцу вводим имя - client_ip, тип - VARCHAR, длина - 15.

Третьему столбцу вводим имя - article_id, тип INT

Сравнение ставим utf8_general_ci, тип InnoDB.


Если Вы работаете с базой данных из консоли - находясь в режиме sql выполняем команду:

CREATE TABLE likes (id INT NOT NULL AUTO_INCREMENT, client_ip VARCHAR(15) NOT NULL, article_id INT NOT NULL, PRIMARY KEY (id)) ENGINE = InnoDB CHARSET=utf8 COLLATE utf8_general_ci;

Далее, для оптимизации таблицы сделаем уникальными связку "IP пользователя" - "ID поста". Это нужно для того, чтобы, если вдруг пользователь попытается проголосовать повторно за один и тот же пост, не происходило лишней записи в базу данных. Таким образом, с одного IP адреса проголосовать за один пост можно будет только один раз.

Выполняем SQL-запрос:

ALTER TABLE likes ADD UNIQUE INDEX (client_ip, article_id);

Далее создаём файл, назовём его like.php

В файле первым делом создаём подключение к базе данных:

<?php
$link = mysqli_connect('имя_хоста', 'имя_пользователя', 'пароль', 'имя_БД');
$link->set_charset('utf8');
$link->query("SET NAMES utf8 COLLATE utf8_general_ci"); 
?>

Если у Вас уже есть подключение к базе данных в отдельном файле, то просто подключаем этот файл через require_once().

Затем в файле like.php создаём переменные и делаем запрос к БД на вставку новых данных:

<?php
$clientIp = $_POST['ip'];

$article_id = $_POST['id'];

$sql = "INSERT INTO likes (id, client_ip, article_id) VALUES (NULL, '$clientIp', '$article_id')";

$query = mysqli_query($link, $sql);
?>

Затем создаём PHP функцию для подсчёта лайков:

<?php
function quantityLikes($postID) { // функция принимает ID поста
    global $link;
    $sql = "SELECT client_ip FROM likes WHERE article_id = '$postID' GROUP BY client_ip"; // выбираем IP из таблицы likes с уникальными значениями
    $query = mysqli_query($link, $sql);
    $likes = mysqli_fetch_all($query, 1);
    return $likes;
}
?>

В результате вызова данной функции мы получим ассоциативный массив со значениями вида:

Array
(
    [0] => Array
        (
            [client_ip] => 77.111.247.27
        )

    [1] => Array
        (
            [client_ip] => 80.92.29.98
        )
    ...
)

Поскольку мы передавали ID конкретного поста, то мы получаем список IP-адресов только для данного поста.

При загрузке страницы нам нужно определять, голосовал ли данный пользователь ранее за данный пост. Т.е. нам нужно определить его IP-адрес и проверить, есть ли он в массиве, полученном нами выше. К сожалению, стандартная функция PHP in_array() не подходит для проверки вхождения значений в ассоциативных массивах, поэтому мы будем использовать свою функцию:

<?php
function is_in_array($array, $key, $key_value) {
      $within_array = false;
      foreach($array as $k=>$v) {
        if(is_array($v)) {
            $within_array = is_in_array($v, $key, $key_value);
            if($within_array == true) {
                break;
            }
        } else {
                if($v == $key_value && $k == $key) {
                        $within_array = true;
                        break;
                }
        }
      }
      return $within_array;
}
?>

Функция возвратит нам true или false в зависимости от того, будет ли присутствовать IP-адрес пользователя в массиве адресов ранее голосовавших пользователей. Вызывать функцию будем со следующими параметрами:

is_in_array($likesArr, 'client_ip', $_SERVER['REMOTE_ADDR'])

Далее заходим в файл шаблона, формирующий наш пост и в верху файла пишем PHP-код:

<?php
$likesArr = quantityLikes($post['id']); // в функцию quantityLikes мы передаём ID текущего поста. В моём блоге - это $post['id']. В Вашем это будет другое значение
$likes = count($likesArr); // считаем лайки с помощью подсчёта общего значения количества элементов массива
?>

Далее в html-разметке вставляем:

<? if(!is_in_array($likesArr, 'client_ip', $_SERVER['REMOTE_ADDR'])): ?>
<i title="Оцените пост"><img src="путь_на_иконку_для_новых_пользователей" class="icon_head" alt="" data-ip="<?=$_SERVER['REMOTE_ADDR']?>" data-post="<?=$post['id']?>"></i> <span id="countLikes"><?=$likes?></span>
<? else : ?>
<i title="Вы уже оценили данный пост"><img src="путь_на_иконку_для_уже_проголосовавших_ранее" class="icon_head noClick" alt=""></i> <span id="countLikes"><?=$likes?></span>
<? endif; ?>

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

В data-параметрах для новых пользователей мы указали IP-адрес и ID данного поста. Эти параметры мы будем использовать в javascript-запросе к серверу при нажатии на иконку лайка.

Javascript:

<script>
// событие загрузки страницы, не включая скрипты и картинки
document.addEventListener("DOMContentLoaded", function() {
    var iconHead = document.querySelector('.icon_head');
    if(iconHead) {
        // считаем количество текущих лайков и увеличиваем на 1
        var countLikes = parseInt(document.getElementById('countLikes').textContent) +1;
        // по клику на иконку
        iconHead.addEventListener('click', function() {
            // увеличиваем цифру лайков на 1
            document.getElementById('countLikes').textContent = countLikes;
            // меняем иконку (в моём случае - закрашенное сердечко)
            this.setAttribute('src', 'путь_на_иконку_для_уже_проголосовавших_ранее');
            // добавляем css класс .noClick
            this.classList.add('noClick');
            // записываем в переменную IP-пользователя из атрибута data-ip
            var clientIp = this.getAttribute('data-ip');
            // записываем в переменную IP-пользователя из атрибута data-post
            var postId = this.getAttribute('data-post');
            // создаём новый XMLHttpRequest для асинхронной передачи параметров на сервер
            var httpRequest = new XMLHttpRequest();
            // указываем файл, на который идёт запрос
            var sendUrl = "/functions/like.php";
            // в параметры записываем IP-клиента и ID статьи
            var sendParams = 'ip='+ clientIp +'&id=' + postId;
            httpRequest.open("POST", sendUrl, true);
            // устанавливаем заголовки
            httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            // отправляем данные на сервер
            httpRequest.send(sendParams);
        })
    }
});
</script>

И напоследок, минимальный набор стилей:

.icon_head {
    height: 15px;
    width: 15px;
    cursor: pointer;
}
.noClick {
    pointer-events: none; /* делаем элемент некликабельным */
}

В итоге мы имеем удобный функционал:

  • считающий лайки;
  • с уникальными значениями в базе данных;
  • с возможностью проголосовать 1 раз только с одного IP;
  • не требующий никаких авторизаций через социальные сети или сервисы;
  • не требующий зависимостей и сторонних библиотек.

Подписывайтесь на группу в ВКонтакте, вступайте в сообщество на Facebook, чтобы всегда быть в курсе актуальных выпусков
Web development blog!

Читайте также:

Пишем свой css фреймворк на Sass

Как подключить чат в поиске Яндекса + крутой онлайн чат для сайта

Делаем свой счётчик просмотров, используя API Метрики