О web-разработке
и даже немного больше...

Образец скрипта голосования (Like / Unlike) в связке AJAX/PHP/MySQL.

like-and-unlikeКак показывает практика, использование различных технологий в связке может дать неплохой результат, и в нашем случае этот факт не стал исключением. Сделаем скрипт голосования («За» / «Против») без перезагрузки страницы. Для реализации нам потребуется библиотека JQuery.

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

posts-table

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

unique_likes

Далее создаем файл, который будет содержать класс для подключения к серверу 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/

Опубликован: 07.02.2013 г.

См. также:

Делаем кнопки «Поделиться в соцсетях»
Стрелочные функции в JS
Мобильное меню для сайта на CSS
Опасность использования атрибута target="_blank"
Бесконечная анимация вращения на CSS
Анимация вращения при наведении курсора
Стилизация выделения номера телефона в мобильных браузерах
Эффекты кнопок для сайта

Комментарии

  1. Андрей пишет:

    А с одной таблицей нельзя сделать?

    1. htmaker пишет:

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

      1. vital пишет:

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

        1. vital пишет:

          Прошу прощения, влез без дела.
          Я проглядел, что posts - это таблица постов, а не самих лайков. :) Просто я представил структуру, где лайки лежат отдельно для разных сущностей. Если данные о кол-ве лайков лежат непосредственно в таблице постов, то конечно структура со второй таблицей - верная.

  2. Абай пишет:

    Спасибо! А как можно сделать для конкретных статей?

    1. htmaker пишет:

      Для статей нужно добавить дополнительный параметр, скажем в таблице со статьями будет поле show_raiting, тип INT(1). Параметр будет отвечать показывать голосование в конкретной статье либо нет. На странице вывода статей делать проверку. Логически 1 - показ, 0 - нет.

  3. Денис пишет:

    Подскажите а можно ли будет сделать так: На стр подгружается инфа допустим название песни которое через некоторое время изменяется и нужно сделать так чтоб названию песни выдавался ид и если юзер нажал на мне нрав или не нрав название этой песни записалась в столбец с названием name в таблице posts и так же выдать ид именно этой песни в таблице unique_likes чтоб когда название песни изменилось и выдало новому названию другой ид можно было поставить нрав или не нрав. Если все это возможно подскажите как заранее большое спасибо!

  4. Миша пишет:

    Расширение mysql было признано устаревшим начиная с PHP 5.5.0 и полностью удалено в версии PHP 7. Похоже вам пора переходить на более современные средства работы с базой

  5. htmaker пишет:

    Первый релиз PHP7 версии был в 2014 году если я не ошибаюсь, статья была написана в 2013.

  6. tomalko пишет:

    я использую свой класс 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();
    }

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *