Простая система лайков для любого сайта без подключения к базе данных на PHP+JS с определением IP посетителя
Мой блог создан на CMS Publii и из коробки нет практически ничего для блога - комментариев, счетчиков просмотра постов и лайков и это даже хорошо.
CMS Publii генерирует чистые статические файлы html в сайт из довольно удобной программы на Windows.
Я создал простую систему лайков, которая подойдет любому сайту и без подключения к базе данных, что для меня важно. Данный скрипт использую на всех своих сайтах и он хорошо себя зарекомендовал. При нажатии на кнопку лайка в списке постов или в одиночным она меняет цвет на красный, счетчик увеличивается +1 и записывается в JSON файл данные id и ip посетителя. Повторно нажать на кнопку не получится, только если сменить IP.
Содержание статьи
Обработчик PHP
Я создал 2 файла. Один обрабатывает и подсчитывает количество лайков, а другой возвращает значения и положил их в корень сайта.
1. like.php
<?php
// Путь к файлу JSON для хранения данных о лайках
$likesFile = 'likes.json';
// Получение данных из POST запроса
$data = json_decode(file_get_contents('php://input'), true);
$postId = $data['postId'];
$ipAddress = $_SERVER['REMOTE_ADDR'];
// Загрузка данных о лайках из файла JSON
$likesData = [];
if (file_exists($likesFile)) {
$likesData = json_decode(file_get_contents($likesFile), true);
}
// Проверка, есть ли уже лайк от этого IP-адреса
if (!isset($likesData[$postId][$ipAddress])) {
// Увеличение счетчика лайков
if (!isset($likesData[$postId])) {
$likesData[$postId] = [];
}
$likesData[$postId][$ipAddress] = true;
// Сохранение данных о лайках в файл JSON
file_put_contents($likesFile, json_encode($likesData));
// Подсчет общего количества лайков для данного поста
$likeCount = count($likesData[$postId]);
// Возвращение значения счетчика лайков в формате JSON
echo json_encode(['likes' => $likeCount]);
} else {
// Если лайк уже был поставлен этим IP-адресом, возвращаем текущее количество лайков
$likeCount = count($likesData[$postId]);
echo json_encode(['likes' => $likeCount]);
}
?>
2. get_likes.php
<?php
// Путь к файлу JSON для хранения данных о лайках
$likesFile = 'likes.json';
// Получение ID поста из запроса
$postId = $_GET['postId'];
// Загрузка данных о лайках из файла JSON
$likesData = [];
if (file_exists($likesFile)) {
$likesData = json_decode(file_get_contents($likesFile), true);
}
// Подсчет общего количества лайков для данного поста
$likeCount = isset($likesData[$postId]) ? count($likesData[$postId]) : 0;
// Возвращение значения счетчика лайков в формате JSON
echo json_encode(['likes' => $likeCount]);
?>
Js код
Его нужно разместить перед закрывающимся тегом </body>
<script>
document.addEventListener("DOMContentLoaded", function() {
const likeButtons = document.querySelectorAll('.like-btn');
likeButtons.forEach(button => {
button.addEventListener('click', function() {
const postId = this.getAttribute('data-post-id');
likePost(postId, this);
});
});
// Загрузка и отображение счетчика лайков и состояния лайка при загрузке страницы
loadLikes();
function likePost(postId, button) {
// Отправка запроса на сервер
fetch('like.php', {
method: 'POST',
body: JSON.stringify({ postId: postId })
})
.then(response => response.json())
.then(data => {
// Обновление отображения счетчика лайков
const likeCountSpan = document.querySelector(`[data-post-id="${postId}"] + .like-count`);
likeCountSpan.innerText = data.likes;
// Добавление класса active к кнопке
button.classList.add('active');
// Сохранение состояния лайка в локальное хранилище
localStorage.setItem(`like_${postId}`, 'liked');
})
.catch(error => console.error('Error:', error));
}
function loadLikes() {
// Загрузка счетчиков лайков и состояния лайка при загрузке страницы
likeButtons.forEach(button => {
const postId = button.getAttribute('data-post-id');
fetchLikes(postId, button);
});
}
function fetchLikes(postId, button) {
fetch(`get_likes.php?postId=${postId}`)
.then(response => response.json())
.then(data => {
// Обновление отображения счетчика лайков
const likeCountSpan = document.querySelector(`[data-post-id="${postId}"] + .like-count`);
likeCountSpan.innerText = data.likes;
// Проверка состояния лайка в локальном хранилище и добавление класса active
if (localStorage.getItem(`like_${postId}`) === 'liked') {
button.classList.add('active');
}
})
.catch(error => console.error('Error:', error));
}
});
</script>
Создание пустого файла likes.json
Просто создайте файл likes.json
и положите в корень вашего сайта. В данный файл будут записываться данные содержащие IP пользователя, который его лайкнул и ID поста.
Пример данных, которые записываются в likes.json
{"7":{"43.163.139.18":true,"213.100.37.245":true}}
...
Чтобы ограничить доступ к данным извне в файле likes.json необходимо внести правила в файле .htaccess. Если его нет, то создать и положить в корень сайта.
<FilesMatch ".(json)$">
deny from all
</FilesMatch>
HTML код вывода счетчика
Данный код нужно добавить, где вы хотите вывести кнопку со счетчиком лайков. Это может быть список постов, одиночный пост, рекомендуемые посты.
<div class="likes-counter">
<button class="like-btn" data-post-id="{{id}}">
<svg width="20" height="18" viewBox="0 0 22 20" xmlns="http://www.w3.org/2000/svg">
<path d="M15.1111 1C18.6333 1 21 4.3525 21 7.48C21 13.8138 11.1778 19 11 19C10.8222 19 1 13.8138 1 7.48C1 4.3525 3.36667 1 6.88889 1C8.91111 1 10.2333 2.02375 11 2.92375C11.7667 2.02375 13.0889 1 15.1111 1Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<span class="like-count">0</span>
</div>
Обратите внимание на атрибут data-post-id="{{id}}"
, в него я получаю id поста. В CMS Publii это делается просто добавив {{id}}. В вашем случае получение id поста может отличаться. Читайте документацию к вашей CMS как получить ID.
Стили CSS
.likes-counter {
display: flex;
align-items: center;
}
.like-btn.active svg {
fill: red;
stroke:red;
}
.like-btn {
background: none;
stroke: black;
fill: white;
margin-right: 5px;
padding: 0;
display: flex;
}
.like-btn:hover {
background: none !important;
}
.like-count {
line-height: 1;
font-size: .8789062495rem;
}
.like-btn svg:hover {
fill: red;
stroke:red;
}
.like-btn:active, .like-btn:focus {
background: none;
}
Результатом будет кнопка в виде сердца и счетчиком справа. При наведении на кнопку меняется цвет на красный, а при нажатии цвет сохраняется. Счетчик учитывает лайки как из списка постов, так и из одиночных.
Вот собственно и все. Если у вас возникают какие-либо сложности, то задавайте вопросы в комментариях.