Realtime Notification with counter in Title - PHP, MySQL, Javascript, Node JS, Socket IO

Realtime Title Bar Notification – PHP, MySQL, Node JS

In this article, we are going to show you, how you can show a real-time notification to your users in their title bar using PHP, MySQL, and Node JS. You can show a notification in a title bar with just PHP and MySQL. But the “real-time” effect can only be achieved with Node JS.

What we will do:

  1. Save notification in database
  2. Display counter in title bar
  3. Show all unread notifications to the user
  4. Mark notification as read
  5. Make notifications real-time

1. Save notifications in MySQL database

First, we need to save the notifications in the database. Notifications can be of any type, for example, “a new message is received” or “your account has been activated” etc. We will create a new file named “send-notification.php“.

<?php

	// connect with database
	$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");

	// create table if not exists
	$sql = "CREATE TABLE IF NOT EXISTS notifications (
		id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
		user_id INTEGER,
		message TEXT,
		is_read BOOLEAN,
		created_at DATETIME
	)";

	// prepare the query
	$statement = $conn->prepare($sql);
	
	// execute the statement
	$statement->execute();

	// user who needs to receive the notification
	$user_id = 565; // replace this your user ID
	$message = "You have received a new message " . time() . ".";
	$is_read = 0;

	// insert in notifications table
	$sql = "INSERT INTO notifications (user_id, message, is_read, created_at) VALUES (?, ?, ?, NOW())";
	$statement = $conn->prepare($sql);
	$statement->execute([
		$user_id, $message, $is_read
	]);

Comments have been added with each line for an explanation. Run the above code and check your database, you will see a new table named “notifications” and also a new row is inserted in that table. Now we need to display this on the user side.

2. Display counter in title bar

We just need to fetch the total number of unread notifications from the database and display them in the user’s title bar. Create a new file named “index.php” and it will have the following code:

<?php

	// start session and login the user
	session_start();

	// you might be saving the session during login,
	// I am hard-coding the value for testing purpose
	$_SESSION["user_id"] = 565;

	// connect with database
	$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");

	// get number of unread notifications
	$sql = "SELECT COUNT(*) AS total_unread_notifications FROM notifications WHERE user_id = ? AND is_read = 0";
	$statement = $conn->prepare($sql);
	$statement->execute([
		$_SESSION["user_id"]
	]);
	$row = $statement->fetch();
	$total_unread_notifications = $row["total_unread_notifications"];

Then we need to fetch this variable in Javascript and prepend it in the title bar. First, we need to create a title tag and a hidden input field where we will put the above variable value.

<!-- title where notification number will be displayed -->
<title>My Website</title>

<!-- save variables in hidden input field to access in Javascript -->
<input type="hidden" id="total-unread-notifications" value="<?php echo $total_unread_notifications; ?>" />

Then we need to get this input field value in Javascript and render it in the title tag. We will create a separate Javascript function to render the title bar because we will need it in multiple situations:

  1. When the page is loaded
  2. When there is new notification (increment)
  3. When a notification is read by user (decrement)
<script>

	// get variables in Javascript
	var totalUnreadNotifications = document.getElementById("total-unread-notifications").value;
	totalUnreadNotifications = parseInt(totalUnreadNotifications);

	// show count in title bar
	showTitleBarNotifications();

	function showTitleBarNotifications() {
		// pattern to check if there is any counter number at the start of title bar
    	var pattern = /^\(\d+\)/;

    	if (totalUnreadNotifications == 0) {
    		document.title = document.title.replace(pattern, "");
			return;
		}

		if (pattern.test(document.title)) {

			// update the counter
			document.title = document.title.replace(pattern, "(" + totalUnreadNotifications + ")");
		} else {

			// prepend the counter
			document.title = "(" + totalUnreadNotifications + ") " + document.title;
		}
	}
</script>

This will first check if the value of variable totalUnreadNotifications is greater than 0. If it is 0, then we will not show any number at all (not even 0). Then we will check if there is already any value in the title bar. If there is any value, then we will simply increment the counter value and re-render the title bar.

If there isn’t any value already in the title bar, then we will simply prepend the counter before the title tag content. At this point, you are seeing the number of unread notifications in your title bar. Now you need to find a way to mark notifications as “read” and decrement the counter.

3. Show all unread notifications to the user

To mark notifications as “read”, we first must show all the notifications to the user which when clicked will be marked as “read”. After that, the counter will be decremented and the title tag will be re-rendered. We will create a new file named “notifications.php” to display all notifications to the user.

<?php

	// start session
	session_start();

	// connect with database
	$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");

	// get all notifications sorting by unread goes first
	$sql = "SELECT * FROM notifications WHERE user_id = ? ORDER BY is_read ASC";
	$statement = $conn->prepare($sql);
	$statement->execute([
		$_SESSION["user_id"]
	]);
	$notifications = $statement->fetchAll();

This will fetch all the notifications of the logged-in user. Now we need to display them in an HTML table. We will simply by displaying a notification message and a button to mark that notification as read.

<!-- show all notifications in a table -->
<table>
	<tr>
		<th>Message</th>
		<th>Action</th>
	</tr>

	<?php foreach ($notifications as $notification): ?>
		<tr>
			<td><?php echo $notification['message']; ?></td>
			<td>
				<!-- show 'read' button only if the notification is un-read -->
				<?php if (!$notification['is_read']): ?>
					<form onsubmit="return markAsRead();">
						<input type="hidden" name="id" value="<?php echo $notification['id']; ?>" />
						<input type="hidden" name="user_id" value="<?php echo $notification['user_id']; ?>" />
						<input type="submit" value="Read" />
					</form>
				<?php endif; ?>
			</td>
		</tr>
	<?php endforeach; ?>
</table>

If you refresh the page now, you will see a list of all notifications with a button “read”. On clicking that button, we need to call an AJAX request to the server to mark this notification as “read” in the MySQL database. We will be using Vanilla JS to do that, no jQuery or any other external library is being used.

Now we need to create this Javascript function that will actually send the AJAX request. We will be using AJAX because there will be a lot of notifications and it will not be a good idea to keep refreshing the page for each notification to be marked as read.

<script>
	// when the read button is clicked
	function markAsRead() {
		// prevent the form from submitting
		event.preventDefault();

		// get the form node
		var form = event.target;

		// create AJAX object
		var ajax = new XMLHttpRequest();

		// set method and URL of request
		ajax.open("POST", "read-notification.php", true);

		// when the status of request changes
		ajax.onreadystatechange = function () {

			// when the response is received from server
			if (this.readyState == 4) {

				// if the response is successful
				if (this.status == 200) {

					// convert the JSON string into Javascript object
					var data = JSON.parse(this.responseText);
					console.log(data);

					// if there is no error
					if (data.status == "success") {

						// remove the 'read' button
						form.remove();

						// [emit read notification event here]
					}
				}
			}
		};

		// create form data object with the form
		var formData = new FormData(form);

		// send the AJAX request with the form data
		ajax.send(formData);
	}
</script>

This will prevent the form from redirecting and calling our Javascript code. After the notification is successfully marked as read from the server, we will remove the “read” button. The last thing we need is a server-side PHP file that will handle this request.

4. Mark notification as read

Now we need to create a new file named “read-notification.php” that will mark this notification as “read”. In this file, we will also check the user_id along with the notification ID to make sure that the notification we are marking is “read” is actually sent to the logged-in user.

<?php

	// start the session
	session_start();

	// connect with database
	$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");

	// get ID from AJAX
	$id = $_POST["id"];

	// mark notification as read
	$sql = "UPDATE notifications SET is_read = 1 WHERE id = ? AND user_id = ?";
	$statement = $conn->prepare($sql);
	$statement->execute([
		$id,
		$_SESSION["user_id"]
	]);

	// send the response back to client
	echo json_encode([
		"status" => "success"
	]);
	exit();

This file will first check that the notification ID sent from AJAX actually refers to the logged-in user. Because someone can try to tamper the client-side code and mark any other user’s notification as “read”. So we must do server-side validation like above.

At this point, if you run the code now, you will be able to see all the notifications in an HTML table with a “Read” button. When clicked, will mark the notification as read and also will remove the “read” button.

If you refresh the “index.php” file, you will now see the counter in the title bar will be decremented. One more thing you can do is to make it real-time, so when there is any notification added, the counter will be incremented in the title bar. And also when the notification is read by the user, then the counter should be decremented automatically.

5. Make notifications real-time

Making these notifications in real-time is crucial. You might have used the WhatsApp Web where you will see that the counter in the title bar automatically gets incremented and decremented based on the number of new notifications you received and the notifications have you read.

Now we need to learn how you can implement this functionality in your project. We will be using the Socket IO JS library for this and we will also create a small Node JS server for this purpose. You can download Socket IO JS from their official site.

After downloading, you need to paste the JS file into your project. You also need to download and install Node JS in your system, you can download it from here.

Setting up Node JS server

After Node JS installation, open command prompt or terminal in your project root directory and run the following command:

npm init

This will ask a couple of questions, you can press “enter” for all questions and it will automatically set the default answer. Then we need to install the required modules for this feature. Run the following command in your terminal:

npm install express http socket.io

This will install the Express, HTTP, and Socket IO module in your Node JS app. To start the server, we need to install another module globally named “nodemon“. So again, run the following command in your terminal:

npm install -g nodemon

Typically when you made changes in your code, you need to manually restart the Node JS server. But it slows down the process during development. So this module automatically restarts the server if there is any change in the server file.

Create a new file named “server.js“, this will be our Node JS server file. Paste the following code in that file, we will explain this in the next step:

// initialize express server
var express = require("express");
var app = express();

// create http server from express instance
var http = require("http").createServer(app);

// include socket IO
var socketIO = require("socket.io")(http, {
	cors: {
		origin: ["http://localhost"]
	}
});

// start the HTTP server at port 3000
http.listen(process.env.PORT || 3000, function () {
	console.log("Server started running...");

	// an array to save all connected users IDs
	var users = [];

	// called when the io() is called from client
	socketIO.on("connection", function (socket) {

		// called manually from client to connect the user with server
		socket.on("connected", function (id) {
			users[id] = socket.id;
		});
	});
});

In this file we are:

  1. Initializing the Express framework and also HTTP module.
  2. Including Socket IO module. You can place your own server URL in the CORS origin array.
  3. Then we are starting the server at port 3000. We use process.env.PORT on deployment.
  4. When a new user is connected with a server, a unique socket ID is generated. We are saving each user’s socket ID in a local array along with his ID from database.

Now is the time to start the server. Run the following command in your terminal to start the server.

nodemon server.js

If you check the terminal, you will see a message “Server started running…” this means that you are ready to send connect your client-side with this server.

Increment counter on new notification

Whenever a new notification is sent to the server, we need to automatically increment the counter in the title bar. We have already created a function in “index.php” that displays the counter in the title bar.

To add this feature we need to perform the following tasks:

  1. Connect socket IO JS on “send-notification.php” file.
  2. Then emit (send) the notification event to the Node JS server along with ID of user.
  3. On Node JS server side, listen to that event and emit the event to the relative user.
  4. Connect socket IO JS on “index.php” file.
  5. Listener for that new notification event.
  6. When that event is received, increment the counter and re-render the title.

The following code goes in the “send-notification.php” file after the notification is inserted in the database:

<!-- save user id -->
<input type="hidden" id="user-id" value="<?php echo $user_id; ?>" />

<!-- include socket IO JS -->
<script src="socket.io.js"></script>

<script>
	// connect with Node JS server
	var socketIO = io("http://localhost:3000");

	// get user ID
	var userId = document.getElementById("user-id").value;

	// send notification to the server
	socketIO.emit("newNotification", userId);
</script>

We are already creating the $user_id variable in the first step. Then we are simply including the socket IO JS library and connect with the Node JS server. Getting the user ID from hidden input field. And finally emitting an event to the server with a user ID.

In your “server.js” listen to this event and emit the event to the user with the same ID.

// when a new notification is received
socket.on("newNotification", function (userId) {

	// send notification to the selected user
	socketIO.to(users[userId]).emit("newNotification", userId);
});

The event has been dispatched from the server to the client. Now the client must listen to this event and when received should increment the counter and re-render the title. Following code goes in your “index.php“:

<!-- include socket IO JS -->
<script src="socket.io.js"></script>

<script>
	// connect with Node JS server
	var socketIO = io("http://localhost:3000");

	// connect user with Node JS server
	var userId = document.getElementById("user-id").value;
	socketIO.emit("connected", userId);

	// when a new notification is received
	socketIO.on("newNotification", function (data) {
		totalUnreadNotifications++;
		showTitleBarNotifications();
	});
</script>

Open “index.php” and “send-notification.php” in separate tabs and refresh both of these pages. Everytime you refresh the send notification page, you will see the title of the index file gets incremented. Now we need to do the same for reading notifications, except that the title bar will be decremented whenever a notification is marked as read.

Decrement counter on read notification

In “notifications.php” first we need to include the socket IO JS library and connect with the server.

<!-- include socket IO JS -->
<script src="socket.io.js"></script>

<script>
	// connect with Node JS server
	var socketIO = io("http://localhost:3000");
</script>

Following code goes in the [emit read notification event here] section:

// send notification to the server
socketIO.emit("notificationRead", form.user_id.value);

Now we need to create a listener for this in our “server.js” file.

socket.on("notificationRead", function (userId) {
	socketIO.to(users[userId]).emit("notificationRead", userId);
});

Similarly, you need to create a listener on user side too in index.php file.

socketIO.on("notificationRead", function (data) {
	totalUnreadNotifications--;
	showTitleBarNotifications();
});

Run the code now and refresh both of your browsers. And try to read some notifications, as soon as you read them, you will see that the counter in the title bar will be decremented too.

Conclusion

So that’s how you can implement a real-time notification system in your website with an unread notification counter in the title bar using simple PHP, Javascript and Node JS. There is no PHP or Javascript framework is used in this tutorial, so you can work with it with any framework in your existing project.

If you face any problem in following this, kindly do let me know in the comments section below.

Download source code

Leave a Reply

Please disable your adblocker or whitelist this site!