3 Steps Simple Like Dislike System In PHP MySQL

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” or “like/dislike” features everywhere. Well, if you want to create your own independent like/dislike system, let us walk through an actual example – 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

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

 

QUICK NOTES

  • Create a database and import 1-database.sql.
  • Change the database settings in 2-lidi-lib.php to your own.
  • Launch 3-demo.php in your browser.
If you spot a bug, feel free to comment below. I try to answer short 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.

 

SCREENSHOT

 

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.

 

 

PHP MYSQL LIKE DISLIKE SYSTEM

All right, let us now get into more details of building a like dislike system with PHP and MYSQL.

 

STEP 1) REACTIONS DATABASE TABLE

1-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=utf8mb4;

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 For this example, we will use -1 for dislike and 1 for like.

 

STEP 2) PHP LIKES/DISLIKES LIBRARY

2A) REACTIONS CLASS

2-lidi-lib.php
<?php
class Reactions {
  // (A) CONSTRUCTOR - CONNECT TO DATABASE
  private $pdo;
  private $stmt;
  public $error;
  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,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_NAMED
    ]);
  } catch (Exception $ex) { exit($ex->getMessage()); }}

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

  // (C) HELPER FUNCTION - RUN SQL
  function query ($sql, $data=null) {
    $this->stmt = $this->pdo->prepare($sql);
    $this->stmt->execute($data);
  }
 
  // (D) GET REACTIONS FOR ID
  function get ($id, $uid=null) {
    // (D1) GET TOTAL REACTIONS
    $reacts = ["react" => [0, 0]]; // [likes, dislikes]
    $this->query(
      "SELECT `reaction`, COUNT(`reaction`) `total`
      FROM `reactions` WHERE `id`=?
      GROUP BY `reaction`", [$id]
    );
    while ($r = $this->stmt->fetch()) {
      if ($r["reaction"]==1) { $reacts["react"][0] = $r["total"]; }
      else { $reacts["react"][1] = $r["total"]; }
    }

    // (D2) GET REACTION BY USER (IF SPECIFIED)
    if ($uid != null) {
      $this->query(
        "SELECT `reaction` FROM `reactions` WHERE `id`=? AND `user_id`=?",
        [$id, $uid]
      );
      $reacts["user"] = $this->stmt->fetchColumn();
    }
 
    // (D3) DONE - RETURN RESULTS
    return $reacts;
  }
 
  // (E) SAVE REACTION
  function save ($id, $uid, $react) {
    // (E1) FORMULATE SQL
    if ($react == 0) {
      $sql = "DELETE FROM `reactions` WHERE `id`=? AND `user_id`=?";
      $data = [$id, $uid];
    } else {
      $sql = "REPLACE INTO `reactions` (`id`, `user_id`, `reaction`) VALUES (?,?,?)";
      $data = [$id, $uid, $react];
    }
 
    // (E2) EXECUTE SQL
    $this->query($sql, $data);
    return true;
  }
}

The class library looks massive at first, but keep calm and look carefully.

  • (A & B) On creating a new Reactions() object, the constructor will automatically connect to the database. The destructor closes the connection.
  • (C) query() is a helper function to run an SQL query.
  • (D & E) There are only 2 “actual functions”.
    • get() Gets the total number of reactions (likes and dislikes) for the given post/video/product ID. If the user ID is provided, it will also get that user’s reaction.
    • save() Self-explanatory, save a user’s reaction. Set $react = 0 to remove the user’s reaction.

 

 

2B) AJAX HANDLER

2-lidi-lib.php
// (F) HANDLE AJAX CALLS
if (isset($_POST["req"])) {
  // (F1) 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", "");
 
  // (F2) DUMMY "USER ID" & "PRODUCT ID"
  $uid = 1; $pid = 900;
 
  // (F3) CREATE NEW CONTENT OBJECT
  $_REACT = new Reactions();
 
  switch ($_POST["req"]) {
    // (F4) INVALID REQUEST
    default: echo "Invalid request"; break;
 
    // (F5) GET REACTIONS
    case "get":
      echo json_encode($_REACT->get($pid, $uid));
      break;
 
    // (F6) SAVE REACTION
    case "save":
      if ($_REACT->save($pid, $uid, $_POST["react"])) {
        echo json_encode($_REACT->get($pid, $uid));
      } else { echo $_REACT->error ; }
      break;
  }
}

The “second half” of the library is an AJAX handler. That is, send a request $_POST["req"] and the required parameters over, and this will process it accordingly.

  • (F1) The database settings, remember to change these to your own.
  • (F2) For this demo, we will use a fixed dummy “user ID” and “product ID”.
  • (F5 & F6) Pretty much “map the AJAX requests to the appropriate library function”.

A quick example of those who are lost – We send $_POST["req"]="save" and $_POST["react"]=1 to 2-lid-lib.php when the user likes the product.

P.S. The class library, database settings, and AJAX endpoint should be in separate files in a good project. I am just being lazy here.

 

 

STEP 3) DUMMY PRODUCT PAGE

3A) THE HTML

3-demo.php
<!-- (A) LOAD LIKE/DISLIKE "WIDGET" -->
<link rel="stylesheet" href="lidi.css">
<script src="lidi.js"></script>
<script src="3-demo.js"></script>

<!-- (B) DUMMY PRODUCT -->
<div id="demowrap">
  <h1>PRODUCT</h1>
  <img src="box.png">
  <div id="demo"></div>
</div>

The only important part here is using <div id="demo"> to generate the like/dislike button. Also, lidi.js and lidi.css is a like/dislike widget that I created. Check the links below if you are interested to learn more.

 

 

3B) THE JAVASCRIPT

3-demo.js
var demo = {
  // (A) SUPPORT FUNCTION - AJAX FETCH
  fetch : (data, load) => {
    // (A1) FORM DATA
    var form = new FormData();
    for (let [k,v] of Object.entries(data)) { form.append(k, v); }

    // (A2) AJAX FETCH
    fetch("2-lidi-lib.php", { method: "post", body : form })
    .then(res => res.text())
    .then(res => load(res))
    .catch(err => console.error(err));
  },

  // (B) INIT
  lidi : null, // like dislike instance
  init : () => {
    // (B1) GET LIKES FROM SERVER
    demo.fetch({ req : "get" }, data => {
      // (B2) DRAW LIKES/DISLIKES BUTTON
      data = JSON.parse(data);
      demo.lidi = lidi({
        hWrap : document.getElementById("demo"),
        status : data.user ? data.user : 0,
        count : data.react,
        change : demo.save
      });
    });
  },

  // (C) SAVE LIKE/DISLIKE REACTION
  save : status => {
    demo.fetch({
      req : "save",
      react : status
    }, res => { try {
      res = JSON.parse(res);
      demo.lidi.recount(res.react);
    } catch (e) { console.error(e); }});
  }
};
window.onload = demo.init;

Not going to explain this line-by-line, so a quick walkthrough:

  1. demo.fetch() A helper function to do an AJAX call to 2-lidi-lib.php.
  2. demo.init() Runs on page load. It gets the like/dislike count from the server and sets up the HTML widget.
  3. demo.save() This is fired when the user changes the like/dislike reaction. Once again, we will send the new reaction to update the server.

 

 

EXTRA BITS & LINKS

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

 

A SMALL NOTE REGARDING THE COUNT

  • As you can see, we are doing a COUNT(*) to get the total number of likes and dislikes.
  • We get the likes/dislikes count when the user first loads the page.
  • Also when the user changes the like/dislike status.

This works for small projects. But there’s a good reason why most social media remove exact and accurate reaction counts – Counting millions of likes is very heavy on system resources. So if you ever get to that stage, do consider other ways to deal with the likes/dislikes count. Maybe cache the SQL, or create a “total count table”.

 

MUST THERE BE A USER SYSTEM?

Technically, we can generate a random ID and set it in a cookie – Use this as a “temporary unique user ID”. But the security concern remains, anyone who knows well enough can create a simple bot to repeat “like and delete the cookie”.

There will be a lot of spam if you open the like/dislike system to the public. So yes, I will recommend keeping like/dislike as a “users only feature”.

 

LINKS & REFERENCES

 

YOUTUBE TUTORIAL

 

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!

14 thoughts on “3 Steps Simple Like Dislike System In PHP MySQL”

  1. Many thanks! This is easy to implement just what I was looking for. Because of a brain damage it is not possible for me anymore to understand all the code but this is very clear and easy to implement. I am wondering if it is possible to use the <alt tag for the images so people who have non or no good visibility also know what buttons there are when their device speaks out the text. And if possible how do I implement this?

  2. Dear Mr. Toh, thank you so much for your tutorials and all the stuff. And also for your wise words in the help and FAQs. Could you (or someone else) please recommend me a site to learn about the $_SESSION for using it in my own project (I’m an absolute beginner but could understand all this up to here)? Is there a way to donate? Many thanks and best wishes from Germany! Andreas

    1. The long learning process for absolute beginners to fully understand:

      1) Start with cookies – https://code-boxx.com/cookies-in-php/
      2) Then, PHP sessions (sessions are built on top of cookies) – https://code-boxx.com/sessions-in-php/
      3) If you are not familiar with OOP, just about PHP OOP tutorial on the Internet – https://www.google.com/search?q=php+oop+tutorial
      4) Working with MySQL database in PHP – https://www.google.com/search?q=php+mysql+pdo+tutorial
      5) Javascript AJAX FETCH – https://www.digitalocean.com/community/tutorials/how-to-use-the-javascript-fetch-api-to-get-data
      6) A simple user login system (the part on user ID, to track user likes and dislikes) – https://code-boxx.com/simple-login-php-mysql/
      7) Or another way to track users without session using JSON Web Tokens (JWT) – https://code-boxx.com/jwt-login-authentication-php-mysql/

      1. Many thanks! I already started to learn php from the beginning. It is quiet interesting and I will see whether an old man can learn it any more 😆. I already have installed the great script SITELOCK for users login (like on my page). Maybe I can use this in combination with your code. Ich will try to find out. All the best for you, Mr. Toh, and again: Is there a way to donate (for you)?!

        Best wishes for 2022 from Germany! Andreas

      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.