Simple Like & Dislike System In PHP MySQL – Free Source Code

Welcome to a tutorial on how to build a simple like and dislike rating system with PHP and MySQL. Social media is big these days and I am sure you have already seen “upvote”, “downvote”, “like”, and “dislike” feature everywhere on Facebook, YouTube, Twitter, and more. Well, if you want to create your own independent like/dislikes system, it really isn’t that difficult.

A basic like/dislike system only requires a couple of key components:

  1. A database table to store the user likes and dislikes.
  2. A PHP library and AJAX handler to manage the likes and dislikes.
  3. Lastly, implementation onto the pages itself.

Let us walk through an actual example in this guide – Read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

TABLE OF CONTENTS

Download & Notes The Database PHP Scripts
Page Implementation Useful Bits & Links The End

 

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

QUICK NOTES

  • Create a database and import the 1a-database.sql file. If you want some dummy entries, also import 1b-dummy.sql.
  • Change the database settings in 2a-reactions.php to your own.
  • Launch 3a-posts.php in your browser.

If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

THE DATABASE

All right, let us now start with the foundation of the system, by creating a database table to hold the likes and dislikes.

 

THE REACTIONS TABLE

1a-database.sql
CREATE TABLE `reactions` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `reaction` tinyint(1) NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `reactions`
  ADD PRIMARY KEY (`id`,`user_id`),
  ADD KEY `reaction` (`reaction`);
Field Description
id Primary and foreign key. The post ID, product ID, video ID – Whatever you want to add a like/dislike button to.
user_id Primary and foreign key. The user who liked/disliked.
reaction 0 for dislike, 1 for like. But this is an open field and you can add your own reaction codes. For example, 2 for love and 3 for sad.

Yep, this table is actually all we need to record the likes and dislikes.

 

 

PHP SERVER-SIDE SCRIPTS

Next, we move on to tackle the server-side scripts and library that will do most of the backend processing.

 

PHP REACTIONS LIBRARY

2a-reactions.php
<?php
class Reactions {
  // (A) CONSTRUCTOR - CONNECT TO DATABASE
  private $pdo;
  private $stmt;
  function __construct () {
    try {
      $this->pdo = new PDO(
        "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET,
        DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
      );
    } catch (Exception $ex) { die($ex->getMessage()); }
  }

  // (B) DESTRUCTOR - CLOSE DATABASE CONNECTION
  function __destruct () {
    $this->pdo = null;
    $this->stmt = null;
  }

  // (C) GET TOTAL REACTIONS
  function get ($id) {
    // (C1) FORMULATE SQL QUERY
    $sql = "SELECT `id`, `reaction`, COUNT(`reaction`) `total` FROM `reactions` WHERE `id` IN (?";
    $sql .= str_repeat(",?", count($id)-1);
    $sql .= ") GROUP BY `id`, `reaction`";

    // (C2) RUN QUERY
    $reactions = [];
    $this->stmt = $this->pdo->prepare($sql);
    $this->stmt->execute($id);
    while ($r = $this->stmt->fetch(PDO::FETCH_NAMED)) {
      // $reactions[ID][REACTION] = TOTAL
      $reactions[$r['id']][$r['reaction']] = $r['total'];
    }
    return $reactions;
  }

  // (D) GET REACTIONS SET BY SPECIFIED USER
  function getUser ($id, $uid) {
    // (D1) FORMULATE SQL QUERY
    $sql = "SELECT * FROM `reactions` WHERE `user_id`=? AND `id` IN (?";
    $sql .= str_repeat(",?", count($id)-1) . ")"; 

    // (D2) GET USER REACTIONS
    $reactions = [];
    array_unshift($id, $uid);
    $this->stmt = $this->pdo->prepare($sql);
    $this->stmt->execute($id);
    while ($r = $this->stmt->fetch(PDO::FETCH_NAMED)) {
      // $reactions[ID] = REACTION
      $reactions[$r['id']] = $r['reaction'];
    }
    return $reactions;
  }

  // (E) SAVE REACTION
  function save ($id, $uid, $react) {
    $this->stmt = $this->pdo->prepare(
      "REPLACE INTO `reactions` (`id`, `user_id`, `reaction`) VALUES (?,?,?)"
    );
    $this->stmt->execute([$id, $uid, $react]);
    return true;
  }

  // (F) DELETE REACTION
  function del ($id, $uid) {
    $this->stmt = $this->pdo->prepare(
      "DELETE FROM `reactions` WHERE `id`=? AND `user_id`=?"
    );
    $this->stmt->execute([$id, $uid]);
    return true;
  }
}

// (G) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_CHARSET', 'utf8');
define('DB_USER', 'root');
define('DB_PASSWORD', '');

// (H) CREATE NEW CONTENT OBJECT
$REACT = new Reactions();

This one looks massive at first, but keep calm and look carefully.

  • On creating a $REACT = new Reactions() object, the constructor will automatically connect to the database The destructor will close the connection when done.
  • There are only 4 functions!
    • function get() This one gets the total number of reactions (likes and dislikes) for the given array of IDs.
    • function getUser() The cousin of the above, this one gets the reactions set by a single user instead.
    • function save() and function del() Self-explanatory. Saves a user’s reaction or delete it.

That’s all. Really.

 

 

REACTIONS AJAX HANDLER

2b-ajax.php
<?php
// (A) INIT
session_start();
$_SESSION['user'] = 1; // For this demo only, fixed to 1
require "2a-reactions.php";
$results = [];

// (B) COMMON FUNCTION - GET REACTIONS 
function get () {
  global $REACT;
  global $results;
  $results['react'] = $REACT->get([$_POST['id']]);
  $results['user'] = $REACT->getUser([$_POST['id']], $_SESSION['user']);
}

// (C) HANDLE REQUEST
switch ($_POST['req']) {
  // (C1) SAVE REACTION
  case "save":
    $results['status'] = $REACT->save($_POST['id'], $_SESSION['user'], $_POST['react']) ? 1 : 0 ;
    if ($results['status']) { get(); }
    else { $results['error'] = $REACT->error; }
    break;

  // (C2) DELETE REACTION
  case "del":
    $results['status'] = $REACT->del($_POST['id'], $_SESSION['user']) ? 1 : 0 ;
    if ($results['status']) { get(); }
    else { $results['error'] = $REACT->error; }
    break;
}

// (D) RESPOND
/* $results = [
 *   "react" => REACTIONS FOR POST/VIDEO/PRODUCT
 *   "user" => USER REACTIONS
 *   "status" => 1 OR 0 (FOR SAVE + DELETE)
 *   "error" => ERROR MESSAGE, IF ANY
 * ] */
echo json_encode($results);

We are no longer living in the Stone Age of the Internet, and a little bit of AJAX action is in place. This script handles the like/dislike button press and sends back the updated reaction counts. How it works is very simple, we post a $_POST['req'] to this script to specify what we want to process, followed by the required parameters.

Request Description
save Updates the like/dislike status.

Parameters – id, react (0 for dislike, 1 for like)

del Removes a like/dislike reaction.

Parameters – id

Take note of the $_SESSION['user'] = 1 here. This should be the user ID in your own system, and yes, it is best to reserve the reactions for registered users only.

 

 

PAGE IMPLEMENTATION

With all the foundations in place, the last step is to just use the library and AJAX handler to build the pages.

 

DUMMY POSTS PAGE

3a-posts.php
<?php
// (A) USER SESSION - FIXED USER ID TO 1 FOR THIS DEMO
session_start();
$_SESSION['user'] = 1;

// (B) DUMMY POSTS 
$posts = [
  "900" => "Foo Bar",
  "901" => "Boo Bar",
  "902" => "Goo Bar",
  "903" => "Koo Bar"
];
$pid = [];
foreach ($posts as $id=>$txt) { $pid[] = $id; }

// (C) GET REACTIONS
require "2a-reactions.php";
$react = $REACT->get($pid);
$ureact = $REACT->getUser($pid, $_SESSION['user']);
 
// (D) OUTPUT HTML ?>
<!-- (D1) CSS + JS -->
<!-- https://cdnjs.com/libraries/font-awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/>
<link rel="stylesheet" href="3b-posts.css"/>
<script src="3c-posts.js"></script>
 
<!-- (D2) POSTS LIST -->
<div id="demo"><?php
  foreach ($posts as $id=>$txt) { 
  $likes = isset($react[$id][1]) ? $react[$id][1] : 0 ;
  $dislikes = isset($react[$id][0]) ? $react[$id][0] : 0 ;
  $reuser = isset($ureact[$id]) ? $ureact[$id] : "" ; ?>
  <div class="prow" data-react="<?=$reuser?>" id="prow<?=$id?>">
    <div class="ptxt"><?=$txt?></div>
    <div class="plike" onclick="react(<?=$id?>, 1)">
      <i class="fa fa-thumbs-up"></i>
      <span class="countlike"><?=$likes?></span>
    </div>
    <div class="pdislike" onclick="react(<?=$id?>, 0)">
      <i class="fa fa-thumbs-down"></i>
      <span class="countdislike"><?=$dislikes?></span>
    </div>
  </div>
  <?php } ?>
</div>

Well, this is a dummy post page. Essentially, this does 2 things:

  • Draws the HTMLof $posts.
  • Use the PHP library to get the total number of likes, and the reacts that the current user made.
    • $react = $REACT->get($pid)
    • $ureact = $REACT->getUser($pid, $_SESSION['user'])

 

 

THE CSS

3b-posts.css
#demo {
  max-width: 600px;
  margin: 0 auto;
}
.prow {
  display: flex;
  background: #fafafa;
  border: 1px solid #ccc;
  padding: 10px;
  margin-bottom: 10px;
}
.ptxt { width: 100%; }
.plike, .pdislike {
  width: 80px; 
  cursor: pointer;
  color: #bbb;
}
.prow[data-react="0"] .pdislike { color: #f12727; }
.prow[data-react="1"] .plike { color: #0cb30c; }
html, body { font-family: arial, sans-serif; }

Just some cosmetics… Feel free to ignore it.

 

 

THE JAVASCRIPT

3c-posts.js
function react (id, like) {
  // (A) GET SELECTED POST
  var prow = document.getElementById("prow"+id);

  // (B) POST DATA
  var data = new FormData(), req = "";
  if (prow.dataset.react=="") { req = "save"; }
  else { req = prow.dataset.react==like ? "del" : "save" }
  data.append("req", req);
  data.append("id", id);
  data.append("react", like);

  // (C) AJAX + UPDATE REACTION COUNT ON LOAD
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "2b-ajax.php");
  xhr.onload = function () {
    // console.log(this.response);
    var res = JSON.parse(this.response),
        dislikes = 0, likes = 0;
    if (res.react[id] != undefined) {
      dislikes = res.react[id][0]==undefined ? 0 : res.react[id][0],
      likes = res.react[id][1]==undefined ? 0 : res.react[id][1];
    }
    prow.dataset.react = req=="del" ? "" : like ;
    prow.getElementsByClassName("countdislike")[0].innerHTML = dislikes;
    prow.getElementsByClassName("countlike")[0].innerHTML = likes;
  };
  xhr.send(data);
}

Remember the AJAX script from earlier? Yep, this single function react() handle the like/dislike button presses and sends out an AJAX request.

 

USEFUL BITS & LINKS

That’s all for the code, and here are a few small extras that may be useful to you.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you to improve your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

6 thoughts on “Simple Like & Dislike System In PHP MySQL – Free Source Code”

      1. No problems here with Chrome, Opera, Edge, and Firefox – Not sure which version of Firefox you are using… Your customizations probably broke it.

Leave a Comment

Your email address will not be published. Required fields are marked *