Как показывает практика, использование различных технологий в связке может дать неплохой результат, и в нашем случае этот факт не стал исключением. Сделаем скрипт голосования («За» / «Против») без перезагрузки страницы. Для реализации нам потребуется библиотека JQuery.
Для хранения наших данных используется MySQL, поэтому предварительно создаем таблицы в нашей базе:
1. Таблица posts – содержит данные постов. Необходимые поля в таблице id, like, unlike, name.
id – уникальный ключ поста;
like – сумма голосов «за»;
unlike – сумма голосов «против»;
name — имя поста;

2. Таблица unique_likes – необходима для проверки уникальности голосов.
post_id – ключ поста (id в таблице posts).
ip_v4 – ip адрес от дублирования голосов.

Далее создаем файл, который будет содержать класс для подключения к серверу MySQL,
дадим ему имя mysql.php
Код:
<?php
# Параметры MySQL
define("DB_HOST","localhost"); # хост
define("DB_NAME","test_like"); # имя базы
define("DB_USER","user"); # имя пользователя
define("DB_PASS","user_pass321"); # пароль
# класс для работы MySQL
class mySQL {
public $DBConnect = false;
function __construct(){
$this->connect();
}
# подключение к базе
private function connect(){
if (@$db = mysql_connect(DB_HOST, DB_USER, DB_PASS)){
if (mysql_select_db (DB_NAME,$db)){
mysql_query("SET NAMES 'UTF8'");
$this->DBConnect = $db;
return true;
} else {
echo 'Не удалось открыть базу данных MySQL: '.mysql_error();
return false;
}
} else {
echo 'Не удалось соединиться с базой данных MySQL: '.mysql_error();
return false;
}
}
# выполнение SQL запроса
# $resType - возвращаемый результат, может быть array/resource
function query($sql,$resType='array'){
$res = mysql_query($sql,$this->DBConnect);
if ($resType == 'resource'){
return $res; # ресурс
} else {
if ($res){
if (mysql_num_rows($res) > 0){
while($arr = mysql_fetch_assoc($res)){
$arRes[] = $arr;
}
return $arRes; # массив
} else {
return false;
}
} else {
echo 'Ошибка выполнения запроса: '.$sql.mysql_error();
return false;
}
}
}
}
?>
Создаем страницу, которая будет показываться пользователю, назовём её index.php
Код:
<?php
require_once('mysql.php'); # библиотека для работы с MySQL
$dbObj = new MySQL();
# при успешном запросе, результат будет в виде массива
$arPostsList = $dbObj->query("SELECT * FROM posts");
?>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
</head>
<body>
<?if (is_array($arPostsList) && count($arPostsList) > 0){?>
<script type="text/javascript">
function doAction(id,type){
$.post('doAjax.php', {id:id, type:type}, function(data){
if(isNaN(parseFloat(data))){
alert(data);
}else{
$('#'+id+'_'+type+'s').text(data);
}
});
}
</script>
<?foreach ($arPostsList as $arPost){?>
<div style="border:1px solid #778899;">
<h2><?=$arPost['name']?></h2>
<a href="javascript:;" onclick="doAction('<?=$arPost['id'];?>','like');">Нравится (<span id="<?=$arPost['id'];?>_likes"><?=$arPost['like'];?></span>)</a>
<a href="javascript:;" onclick="doAction('<?=$arPost['id'];?>','unlike');">Не нравится (<span id="<?=$arPost['id'];?>_unlikes"><?=$arPost['unlike'];?></span>)</a>
</div>
<?}
}?>
</body>
</html>
Создаем обработчик, который собственно и будет выполнять всю основную работу, назовём файл doAJAX.php.
Код:
<?php
require_once('mysql.php'); # библиотека для работы с MySQL
$dbObj = new MySQL();
if(isset($_POST['id']) && isset($_POST['type'])){
$arULike = $dbObj->query('
SELECT * FROM unique_likes
WHERE post_id="'.(int)$_POST['id'].'"
AND ip_v4="'.$_SERVER['REMOTE_ADDR'].'"');
if(!$arULike){
if ($_POST['type']=='like'){
$dbObj->query('
UPDATE posts
SET `like`=`like`+1
WHERE id="'.(int)$_POST['id'].'"','resource');
$arSNum = $dbObj->query('
SELECT `like`
FROM posts
WHERE id="'.(int)$_POST['id'].'"
LIMIT 1');
echo $arSNum[0]['like'];
} elseif($_POST['type']=='unlike'){
$dbObj->query('
UPDATE posts
SET `unlike`=`unlike`+1
WHERE id="'.(int)$_POST['id'].'"','resource');
$arSNum = $dbObj->query('
SELECT `unlike`
FROM posts
WHERE id="'.(int)$_POST['id'].'"
LIMIT 1');
echo $arSNum[0]['unlike'];
}
$dbObj->query('INSERT INTO unique_likes (`post_id`,`ip_v4`)
VALUES ("'.(int)$_POST['id'].'","'.$_SERVER['REMOTE_ADDR'].'")','resource');
} else {
echo 'Вы уже проголосовали';
}
}
?>
Итак, в итоге у нас должны получиться следующие файлы:
mysql.php – файл подключения к БД MySQL.
doAJAX.php – обработчик AJAX запросов.
index.php – страница, показываемая пользователю.
Исходники в архиве:
https://href.kz/example/like-unlike/files.rar
Рабочий пример:
https://href.kz/example/like-unlike/
А с одной таблицей нельзя сделать?
Думаю можно, однако хранить такие вещи в разных таблицах более предпочтительнее с точки зрения удобства работы с данными, а так же производительности при большом кол-ве записей в таблицах.
А какая может быть проблема с большим количеством даных, если подразумевается, что один посетитель может поставить только один лайк или анлайк? Т.е. с каждым действием у тебя создается одинаковое количество записей в обеих таблицах. Поэтому целесообразней хранить IP в той же таблице, где и лайки, а дальше выбирать по ключам post_id и IP для проверки уникальности
Прошу прощения, влез без дела.
Я проглядел, что posts - это таблица постов, а не самих лайков. :) Просто я представил структуру, где лайки лежат отдельно для разных сущностей. Если данные о кол-ве лайков лежат непосредственно в таблице постов, то конечно структура со второй таблицей - верная.
Спасибо! А как можно сделать для конкретных статей?
Для статей нужно добавить дополнительный параметр, скажем в таблице со статьями будет поле show_raiting, тип INT(1). Параметр будет отвечать показывать голосование в конкретной статье либо нет. На странице вывода статей делать проверку. Логически 1 - показ, 0 - нет.
Подскажите а можно ли будет сделать так: На стр подгружается инфа допустим название песни которое через некоторое время изменяется и нужно сделать так чтоб названию песни выдавался ид и если юзер нажал на мне нрав или не нрав название этой песни записалась в столбец с названием name в таблице posts и так же выдать ид именно этой песни в таблице unique_likes чтоб когда название песни изменилось и выдало новому названию другой ид можно было поставить нрав или не нрав. Если все это возможно подскажите как заранее большое спасибо!
Расширение mysql было признано устаревшим начиная с PHP 5.5.0 и полностью удалено в версии PHP 7. Похоже вам пора переходить на более современные средства работы с базой
Первый релиз PHP7 версии был в 2014 году если я не ошибаюсь, статья была написана в 2013.
я использую свой класс DB но запросы не чем не отличаются... Здесь не только проверка ip но и запись если база пуста... (пригодится)
if(isset($_GET['id']) && isset($_GET['golos']) && in_array($_GET['golos'], array('up', 'down'))) {
$id = (int)$_GET['id'];
$arULike = $db->select('SELECT * FROM unique_likes WHERE post_id="'.$id.'" AND ip_v4="'.get_client_ip().'"');
if(!$arULike){
$is_posts = $db->select('SELECT * FROM posts WHERE `id`="'.$id.'"');
if (empty($is_posts)) {
$db->select('INSERT INTO posts (`id`,`like`,`unlike`) VALUES ("'.$id.'","0","0")');
}
if ($_GET['golos']=='up') {
$db->select('UPDATE `posts` SET `like`=`like`+1 WHERE `id`="'.$id.'"');
$arSNum = $db->select('SELECT `like` FROM `posts` WHERE `id`="'.$id.'" LIMIT 1');
echo json_encode(array('like' => $arSNum[0]['like']));
} else if ($_GET['golos']=='down') {
$db->select('UPDATE `posts` SET `unlike`=`unlike`+1 WHERE `id`="'.$id.'"');
$arSNum = $db->select('SELECT `unlike` FROM `posts` WHERE `id`="'.$id.'" LIMIT 1');
echo json_encode(array('unlike' => $arSNum[0]['unlike']));
}
$db->select('INSERT INTO unique_likes (`post_id`,`ip_v4`) VALUES ("'.$id.'","'.get_client_ip().'")');
} else {
echo json_encode(array('err' =>'Вы уже проголосовали'));
}
exit();
}