Social networking site in Laravel – Node JS, Socket IO

When you hear the word “social networking site”, the first name that came to your mind must be Facebook. Then Instagram, Twitter, etc. We create a social networking site project just to give you an idea of how things work. It is not the exact code used in tech giants like Facebook. But it gives you an idea of how they do it.

Demo

FeaturesFreePremium ($100)
AuthenticationYesYes
Profile UpdateYesYes
Create posts (with images and videos)YesYes
Like, comments and repliesYesYes
Share postsYesYes
Friends post on your wallYesYes
Search usersYesYes
Create friendsYesYes
Admin panelYesYes
Email verificationNoYes
Reset passwordNoYes
NotificationsNoYes
Realtime post update and deleteNoYes
NoYes
Search pages, and groupsNoYes
Create pages, and groupsNoYes
Private user-to-user chatNoYes
List of people who viewed your profileNoYes
Infinite scrollNoYes
people who liked and shared your postNoYes
Chat messages encryptionNoYes
Customer supportNoYes
Ban users, posts, pages, and groupsNoYes
Adult image validationNoYes
Show emails generated by systemNoYes
Online / offline statusNoYes
User last sceneNoYes
User activity logsNoYes

Previously, we create a Social Networking Site in Node JS and Mongo DB. But many people were asking that we create the same project in Laravel too, for PHP lovers. So here it is.

We have added 4 more features to it.

  1. Track system mails: All the emails sent from the system (Mail::to) function will be stored in a database. And the admin can view all the emails from the admin panel.
  2. Online/offline status: Now you can know when your friends are online and when they are offline. This will be helpful because you can just leave a message if the person is currently offline.
  3. Last scene of the user: You can also see your friend’s last scene active. This will help in situations like earthquakes etc. you can know which friends are not active in recent times.
  4. Track user activity: Admin can view the activities of users like when they are logged in when they created a page when they joined a group etc.

Load more Node JS button with Mongo DB

In this tutorial, we are going to teach you how you can create a load more Node JS button with MongoDB in your web project. “Load more” means that we will be displaying a few records, let’s say 5 when the page loads. Then we will display a button that when clicked will fetch the next 5 records. It is similar to the Facebook infinite scroll, where when you reach the end of the page, it automatically fetched the next posts. If you prefer a video tutorial over a textual tutorial, you can find it below:

Setup the server

Make sure you have installed Node JS and Mongo DB in your system. To view the data in Mongo DB, you will need a software called Mongo DB Compass. That can be installed during Mongo DB installation. Using Mongo DB Compass, create a database named “loadmore_nodejs_mongodb”. Inside this database, you need to create a collection named “users”. Inside this collection, you can add 10 records for testing. I have added the name and age of each user, the ID is automatically generated by Mongo DB.

Then you need to create an empty folder anywhere on your computer. And create a new file inside it named “server.js”. At the same time, open your command prompt or Terminal in this folder. You can run the following command to enter this folder:

cd "path of folder"

While being inside the folder, run the following command to initialize it as an NPM:

npm init

After that, you need to install some modules using the following command:

npm install express http mongodb ejs express-formidable
  • We will be using an express framework.
  • HTTP module will be used to start the server at a specific port.
  • Mongo DB module will be used to connect and interact with the Mongo DB database.
  • EJS will be used to render HTML files.
  • Express formidable will be used to receive HTTP POST values, which we will be sending from AJAX.

If you do not have a nodemon module you can install it with this command:

npm install -g nodemon

Nodemon command helps you to automatically restart the server if there is any change in the server.js file. Now in server.js, initialize express framework. Then create an HTTP server object and start the server at port 3000.

// initialize express framework
var express = require("express");
var app = express();
 
// create http server
var http = require("http").createServer(app);

// start the server
http.listen(3000, function () {
    console.log("Server started at port 3000");
});

Run nodemon command to start the server.

nodemon server.js

Connecting Node JS with Mongo DB

Now we need to connect our Node JS Express app with Mongo DB. We have already installed the Mongo DB module. Now we need to include the Mongo DB and Mongo Client objects. Place the following lines in your server.js file before calling the HTTP listen function:

// include mongo DB module
var mongodb = require("mongodb");
var mongoClient = mongodb.MongoClient;

Now after line 10 from previous code, place the following lines to connect with database:

// connect with mongo DB server and database
mongoClient.connect("mongodb://localhost:27017", {
    useUnifiedTopology: true
}, function (error, client) {
    var database = client.db("loadmore_nodejs_mongodb");
    console.log("Database connected.");
});

Display HTML file

Now we need to show an empty table where data will be populated dynamically. We will be using EJS to render the HTML file. First, we need to tell our Express app that we will be using the EJS engine. So add the following lines before connecting the HTTP server in server.js:

// set the view engine as EJS for displaying HTML files
app.set("view engine", "ejs");

Now we need to create a GET route that when accessed from the browser will display an HTML page. Place the following lines after line 6 from the previous code:

// create a GET HTTP route to show page
app.get("/", function (request, result) {
    // render an HTML page
    result.render("index");
});

Now we need to create a folder named “views” and inside this folder, create a file named “index.ejs”. Inside this file, we will create a table, and give an ID to the <tbody> because we will be displaying data dynamically. And also a load more button.

<!-- views/index.ejs -->

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Number</th>
            <th>Age</th>
        </tr>
    </thead>

    <tbody id="data"></tbody>
</table>

<button type="button" onclick="getData();">
    Load More
</button>

Now you can access it by entering the following URL in your browser:

http://localhost:3000/

Get data from Mongo DB

Now we need to fetch data from the database in which a way that it will get 2 records each time a button is clicked. But the first 2 records will be fetched when the page loads. So create a script tag and create a variable that will be incremented each time that button is pressed. This variable will be used to skip the records to fetch the next ones.

<script>

    // Starting position to get new records
    var startFrom = 0;

    window.addEventListener("load", function () {
        // Calling the function on page load
        getData();
    });

</script>

Now we need to create that getData() function in index.ejs file. This will send an AJAX request to the route “load-more” with a method POST. We will also attach our startFrom variable with the AJAX object (line 45). When the response is successfully received from the server (line 15), it will be in a JSON string. So we convert that into Javascript arrays and objects (line 20). Then we are appending the newly fetched data in our tbody tag. And finally, we are incrementing the startFrom variable with the number of records we want to show in each AJAX call.

// This function will be called every time a button pressed 
function getData() {
    // Creating a built-in AJAX object
    var ajax = new XMLHttpRequest();

    // tell the method and URL of request
    ajax.open("POST", "http://localhost:3000/load-more", true);

    // Detecting request state change
    ajax.onreadystatechange = function () {

        // Called when the response is successfully received
        if (this.readyState == 4) {

            if (this.status == 200) {
                // For debugging purpose only
                // console.log(this.responseText);

                // Converting JSON string to Javasript array
                var data = JSON.parse(this.responseText);
                var html = "";
         
                // Appending all returned data in a variable called html
                for (var a = 0; a < data.length; a++) {
                    html += "<tr>";
                        html += "<td>" + data[a]._id + "</td>";
                        html += "<td>" + data[a].name + "</td>";
                        html += "<td>" + data[a].age + "</td>";
                    html += "</tr>";
                }
         
                // Appending the data below old data in <tbody> tag
                document.getElementById("data").innerHTML += html;

                // number of records you want to show per page
                var limit = 2;
         
                // Incrementing the offset so you can get next records when that button is clicked
                startFrom = startFrom + limit;
            }
        }
    };

    var formData = new FormData();
    formData.append("startFrom", startFrom);

    // Actually sending the request
    ajax.send(formData);
}

Now we need to create a POST route in our server.js. Before creating a POST route, we need to tell our Express app that we will be using the Express-Formidable module to get values (e.g. startFrom) from AJAX requests. So paste the following lines before starting HTTP server:

// server.js

// used to get POST field values
var formidable = require("express-formidable");
app.use(formidable());

Now write the following lines after the Mongo DB is connected:

// create a POST HTTP route to get data
app.post("/load-more", async function (request, result) {
 
    // number of records you want to show per page
    var limit = 2;
 
    // get records to skip
    var startFrom = parseInt(request.fields.startFrom);
 
    // get data from mongo DB
    var users = await database.collection("users").find({})
        .sort({ "id": -1 })
        .skip(startFrom)
        .limit(limit)
        .toArray();
 
    // send the response back as JSON
    result.json(users);
});

If you run the code now, you will see 2 records when the page loads. On clicking the load more button, 2 more records will be fetched, and so on.

Styling the table – CSS

At this point, you have successfully created a feature where you can display a few records when the page loads. And further records when user clicks a “load more” button. But we can give a few styles just to make it look good. The following styles will:

  • Give 1-pixel black border to the table and all its headings and data tags.
  • border-collapse will merge all the borders into one.
  • We are giving padding (distance between border and content) to all headings and data tags.
  • Give some margin from the bottom to the table to have some space between the table and load more button.
table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
}
th, td {
    padding: 25px;
}
table {
    margin-bottom: 20px;
}

Now that our load more Node JS button is fully functional. We can also try another approach that is usually called “Infinite scroll”.

Infinite scroll

You can also use an “infinite scroll” like Facebook. Instead of displaying a button to load more data, more data will be fetched when the user scrolled to the bottom. No need to change the Node JS code that we used to load more button. For that, first you need to include jQuery.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Then you can replace your window onload event listener with the following:

var loadMore = true;

window.addEventListener("load", function () {
    // Calling the function on page load
    getData();

    $(window).bind('scroll', function() {
        if(!loadMore && $(window).scrollTop() >= $('#data').offset().top + $('#data').outerHeight() - window.innerHeight) {
            // console.log('end reached');
            loadMore = true;
            getData();
        }
    });
});

And finally in your ajax.onreadystatechange listener, when you successfully append the data in the <tbody> tag, keep the infinite scroll working if there are more records.

if (data.length > 0) {
    loadMore = false;
}

So that’s how you can create a load more Node JS button with Mongo DB.

[wpdm_package id=’1251′]

Pagination – Node JS, Mongo DB, Express

In this tutorial, we are going to create a simple pagination program in Node JS and Mongo DB. For the sake of simplicity, we will be using the Express framework. If you prefer a video tutorial over a textual tutorial, then you can follow the video tutorial below:

Video tutorial

Pagination – Node JS, Mongo DB, Express

Mongo DB data

First, we are going to fill the data in Mongo DB. You can apply this tutorial to your own collections and documents. Or you can import the following (at the end) JSON file in your database using Mongo DB compass. You need to create a database named “pagination_nodejs_mongodb” before importing the file.

Setup the project

Create an empty new folder and enter it with the following commands from Terminal:

mkdir pagination-nodejs-mongodb
cd pagination-nodejs-mongodb

Once in the folder, you can install the required modules by running the following commands:

npm install express http mongodb ejs
npm install -g nodemon

The express framework is used to create web applications and APIs, and we will be creating an API to fetch the data for pagination. HTTP module will be used to start the server at a specific port. Mongo DB module will be used to connect and interact with the Mongo DB database. And finally, EJS will be used to render HTML files.

Create a file named “server.js” and write the following code in it:

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

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

// start the server
http.listen(3000, function () {
    console.log("Server started at port 3000");
});

Run the following command to start the server.

nodemon server.js

This will start the server at port 3000. If you open your terminal, you will see the above message.

Pagination

Now you need to include the Mongo DB module, write the following lines before line 8.

// include mongo DB module
var mongodb = require("mongodb");
var mongoClient = mongodb.MongoClient;
var ObjectId = mongodb.ObjectId;

Then you can connect with the Mongo DB server. You need to write the following lines inside http.listen function callback (2nd parameter):

// connect with mongo DB server and database
mongoClient.connect("mongodb://localhost:27017", {
    useUnifiedTopology: true
}, function (error, client) {
    var database = client.db("pagination_nodejs_mongodb");
    console.log("Database connected.");
});

If you check your terminal now, you will see a second message that your database has been connected. Now we need to create a GET route which when accessed will display 2 users per page from the users collection data. So paste the following lines after the database is connected:

// create a GET HTTP route
app.get("/", async function (request, result) {

    // number of records you want to show per page
    const perPage = 2

    // total number of records from database
    const total = await database.collection("users").countDocuments()

    // Calculating number of pagination links required
    const pages = Math.ceil(total / perPage)

    // get current page number
    const pageNumber = parseInt(request.query.page || 1)

    // get records to skip
    const startFrom = (pageNumber - 1) * perPage

    // get data from mongo DB using pagination
    var users = await database.collection("users").find({})
        .sort({ "id": -1 })
        .skip(startFrom)
        .limit(perPage)
        .toArray();

    // render an HTML page with number of pages, and users data
    result.render("index", {
        "pages": pages,
        "users": users
    });
});

Comments have been added with each line for an explanation. To display the HTML file, we need to tell the Express framework that we will be using the EJS engine. Write the following line before the http.listen function:

// set the view engine as EJS for displaying HTML files
app.set("view engine", "ejs");

Create a folder named “views” at the root of your project. Inside the views folder, create a file named “index.ejs”. Following will be the content of “index.ejs” file:

<table>
    <tr>
        <th>Name</th>
        <th>Age</th>
    </tr>

    <tbody>
        <% for (var a = 0; a < users.length; a++) { %>
        <tr>
            <td><%= users[a].name  %></td>
            <td><%= users[a].age  %></td>
        </tr>
        <% } %>
    </tbody>
</table>

<ul class="pagination">
    <% for (var a = 1; a <= pages; a++) { %>
    <li>
        <a href="?page=<%= a; %>">
            <%= a; %>
        </a>
    </li>
    <% } %>
</ul>

You can run the project from browser by accessing the URL: http://localhost:3000/ and you will see 2 pages on first page along with pagination links at the bottom. On clicking the other page link, you will see further records.

[wpdm_package id=’1232′]

Task management & time tracking script – Javascript

We are going to create customized task management and time tracking script using simple HTML and Javascript. Since we are creating our own script, so we can customize it as much as we need. You can check the demo from here.

Video tutorial

Include libraries

First, we need to include all the libraries that we are going to use. We will be using Bootstrap for design and SweetAlert for displaying pop-up messages.

<!-- to make responsive -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<!-- include bootstrap css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" />

<!-- include jquery and bootstrap js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.min.js"></script>

<!-- include sweetalert for displaying dialog messages -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/2.1.2/sweetalert.min.js"></script>

Add project

Then we are going to create a button that when clicked will display a Bootstrap modal to add a task.

<div class="container" style="margin-top: 50px; margin-bottom: 50px;">
    
    <!-- button to add task -->
    <div class="row" style="margin-bottom: 50px;">
        <div class="col-md-12">
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTaskModal">Add Task</button>
        </div>
    </div>

</div>

Then we are going to create a Bootstrap modal. It will have a form with project and task name fields. It will also have a dropdown from which the user can select his already created projects.

<!-- modal to add project and task -->
<div class="modal fade" id="addTaskModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Add Task</h5>
                <button class="close" type="button" data-dismiss="modal">x</button>
            </div>

            <div class="modal-body">
                <form method="POST" onsubmit="return taskObj.addTask(this);" id="form-task-hour-calculator">
                    
                    <!-- select project from already created -->
                    <div class="form-group">
                        <label>Project</label>
                        <select name="project" id="add-task-project" class="form-control" required></select>
                    </div>

                    <!-- create new project -->
                    <div class="form-group">
                        <label>New Project</label>
                        <input type="text" name="new_project" id="add-project" class="form-control" placeholder="Project Name">

                        <button type="button" onclick="taskObj.addProject();" class="btn btn-primary" style="margin-top: 10px;">Add Project</button>
                    </div>

                    <!-- enter task -->
                    <div class="form-group">
                        <label>Task</label>
                        <input type="text" name="task" class="form-control" placeholder="What are you going to do ?" required />
                    </div>
                </form>
            </div>

            <!-- form submit button -->
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="submit" form="form-task-hour-calculator" class="btn btn-primary">Add Task</button>
            </div>
        </div>
    </div>
</div>

Then we need to create a Javascript function “addProject” inside the “taskObj” object. It will first check if there is any project selected, if not, then it will show an error message. Then it will create an empty array in local storage if not already created. Then it will create a new project object with empty “tasks” array. Finally, it will push the project into an array and update the local storage value, and also it will reload the projects and tasks.

// main object
var taskObj = {

    // local storage key
    key: "projects",

    // add project
    addProject: function () {

        // check if project is selected
        if (document.getElementById("add-project").value == "") {
            swal("Please enter project name");
            return false;
        }

        // initialize local storage if not already initialized
        var option = "";
        if (localStorage.getItem(this.key) == null) {
            localStorage.setItem(this.key, "[]");
        }

        // get stored object from local storage
        var data = JSON.parse(localStorage.getItem(this.key));

        // project object
        var project = {
            id: data.length,
            name: document.getElementById("add-project").value,
            tasks: []
        };

        // push new project in local storage
        data.push(project);
        localStorage.setItem(this.key, JSON.stringify(data));

        // re-load all projects
        this.loadAllProjects();

        // show all tasks
        this.showAllTasks();
    },

};

To load all the projects, we will be using the following 2 functions inside this object:

// get all stored projects
getAllProjects: function() {
    if (localStorage.getItem(this.key) == null) {
        localStorage.setItem(this.key, "[]");
    }
    return JSON.parse(localStorage.getItem(this.key))
},

// load all projects in dropdown
loadAllProjects: function () {
    var projects = taskObj.getAllProjects();
    projects = projects.reverse();
    var html = "<option value=''>Select Project</option>";
    for (var a = 0; a < projects.length; a++) {
        html += "<option value='" + projects[a].id + "'>" + projects[a].name + "</option>";
    }
    document.getElementById("add-task-project").innerHTML = html;
    document.getElementById("form-task-hour-calculator-all-projects").innerHTML = html;
},

We will do the “showAllTasks” function later. Now, when the page loads, we need to fetch all the projects and tasks and display them.

// when page loads
window.addEventListener("load", function () {
    // show all projects and tasks
    taskObj.loadAllProjects();
    taskObj.showAllTasks();
});

At this point, you will be able to create projects and see them in the dropdown. Now we need to add tasks.

Add task

To add a task, we will get the project and task name. Then we will push the newly created task object into the “tasks” array. Finally, we will update the local storage value, hide the Bootstrap modal and reload the tasks.

// add new task
addTask: function (form) {

    // get selected project and entered task
    var project = form.project.value;
    var task = form.task.value;

    // add task in project's array
    var projects = this.getAllProjects();
    for (var a = 0; a < projects.length; a++) {
        if (projects[a].id == project) {
            var taskObj = {
                id: projects[a].tasks.length,
                name: task,
                status: "Progress", // Progress, Completed
                isStarted: false,
                logs: [],
                started: this.getCurrentTimeInTaskStartEndFormat(),
                ended: ""
            }
            projects[a].tasks.push(taskObj);
            break;
        }
    }

    // update local storage
    localStorage.setItem(this.key, JSON.stringify(projects));

    // hide modal
    jQuery("#addTaskModal").modal("hide");
    jQuery('.modal-backdrop').remove();

    // re-load all tasks
    this.showAllTasks();

    // prevent form from submitting
    return false;
},

You might have see the function “getCurrentTimeInTaskStartEndFormat”. Our task management script will save the date and time in format YYYY-MM-DD HH:mm:ss e.g. 2021-06-15 20:53:15.

// get current datetime in proper format (e.g. 2021-06-15 20:53:15)
getCurrentTimeInTaskStartEndFormat() {
    let current_datetime = new Date();
    var date = current_datetime.getDate();
    date = (date < 10) ? "0" + date : date;
    var month = (current_datetime.getMonth() + 1);
    month = (month < 10) ? "0" + month : month;
    var hours = current_datetime.getHours();
    hours = (hours < 10) ? "0" + hours : hours;
    var minutes = current_datetime.getMinutes();
    minutes = (minutes < 10) ? "0" + minutes : minutes;
    var seconds = current_datetime.getSeconds();
    seconds = (seconds < 10) ? "0" + seconds : seconds;
    let formatted_date = current_datetime.getFullYear() + "-" + month + "-" + date + " " + hours + ":" + minutes + ":" + seconds;
    return formatted_date;
},

Show all tasks

To show all tasks, we need to create a table where we will display all tasks created.

<!-- show all tasks -->
<table class="table">
    <caption class="text-center">All Tasks</caption>
        <tr>
            <th>Task</th>
            <th>Project</th>
            <th>Status</th>
            <th>Duration</th>
            <th>Date</th>
            <th>Action</th>
        </tr>

    <tbody id="all-tasks"></tbody>
</table>

Now is the time to create a function “showAllTasks” in our “taskObj” object. This will be a long function, so we will explain the working of this function step-by-step:

// show all tasks in table
showAllTasks: function () {
    var html = "";

    // get all projects
    var projects = this.getAllProjects();
    for (var a = 0; a < projects.length; a++) {
        projects[a].tasks = projects[a].tasks.reverse();

        // get tasks in each project
        for (var b = 0; b < projects[a].tasks.length; b++) {
            html += "<tr>";
                html += "<td>" + projects[a].tasks[b].name + "</td>";
                html += "<td>" + projects[a].name + "</td>";
                if (projects[a].tasks[b].isStarted) {
                    html += "<td><label class='started'>Started</label></td>";
                } else {
                    if (projects[a].tasks[b].status == "Completed") {
                        html += "<td><label class='completed'>" + projects[a].tasks[b].status + "</label></td>";
                    } else {
                        html += "<td>" + projects[a].tasks[b].status + "</td>";
                    }
                }

                // get total duration of each task using it's logs
                var duration = 0;
                for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                    var log = projects[a].tasks[b].logs[c];
                    if (log.endTime > 0) {
                        duration += log.endTime - log.startTime;
                    }
                }

                // convert millisecond into hours, minutes and seconds
                duration = Math.abs((duration / 1000).toFixed(0));
                var hours = Math.floor(duration / 3600) % 24;
                hours = (hours < 10) ? "0" + hours : hours;
                // var days = Math.floor(diff / 86400);
                var minutes = Math.floor(duration / 60) % 60;
                minutes = (minutes < 10) ? "0" + minutes : minutes;
                var seconds = duration % 60;
                seconds = (seconds < 10) ? "0" + seconds : seconds;

                // show timer if task is already started
                if (projects[a].tasks[b].isStarted) {
                    var dataStartedObj = {
                        "duration": duration,
                        "project": projects[a].id,
                        "task": projects[a].tasks[b].id
                    };
                    html += "<td data-started='" + JSON.stringify(dataStartedObj) + "'>" + hours + ":" + minutes + ":" + seconds + "</td>";
                } else {
                    html += "<td>" + hours + ":" + minutes + ":" + seconds + "</td>";
                }

                // show task duration if completed
                if (projects[a].tasks[b].status == "Completed") {
                    html += "<td>" + projects[a].tasks[b].started + "<br><span style='margin-left: 30px;'>to</span><br>" + projects[a].tasks[b].ended + "</td>";
                } else {
                    html += "<td>" + projects[a].tasks[b].started + "</td>";
                }

                // form to change task status
                html += "<td>";
                    html += "<form method='POST' id='form-change-task-status-" + projects[a].id + projects[a].tasks[b].id + "'>";
                        html += "<input type='hidden' name='project' value='" + projects[a].id + "'>";
                        html += "<input type='hidden' name='task' value='" + projects[a].tasks[b].id + "'>";
                        html += "<select class='form-control' name='status' onchange='taskObj.changeTaskStatus(this);' data-form-id='form-change-task-status-" + projects[a].id + projects[a].tasks[b].id + "'>";
                            html += "<option value=''>Change status</option>";
                            if (projects[a].tasks[b].isStarted) {
                                html += "<option value='stop'>Stop</option>";
                            } else {
                                html += "<option value='start'>Start</option>";
                            }
                            if (projects[a].tasks[b].status == "Progress") {
                                html += "<option value='complete'>Mark as Completed</option>";
                            } else {
                                html += "<option value='progress'>Make in Progress Again</option>";
                            }
                            html += "<option value='delete'>Delete</option>";
                        html += "</select>";
                    html += "</form>";
                html += "</td>";
            html += "</tr>";
        }
    }
    document.getElementById("all-tasks").innerHTML = html;
},

The step number corresponds to the highlighted line above.

  1. First, we are looping through all projects and each project’s tasks.
  2. Displaying the task name and project name.
  3. If the task status is “started” then displaying a started message. (we will do this later).
  4. And if the task status is “completed”, then displaying a message for the completed task.
  5. Then we will get the total duration of each task.
  6. The duration will be in milliseconds, so we will convert that into days, hours, minutes, and seconds.
  7. If the task is started, then we will attach an attribute “data-started” to the <td> tag. This will allow us to continuously update the timer every second.
  8. And if the task is completed, then we will display the start and end times of the task. So you can know when the task started and when it is finished.
  9. And finally, we are creating a form from which we can change the status of the task.

Change task status

Now we need to create a function to change the status of the task. Again, this will be a long function, we will explain that step-by-step too.

// change task status
changeTaskStatus: function (self) {

    // if task is not selected
    if (self.value == "") {
        return;
    }

    // loop through all projects
    var formId = self.getAttribute("data-form-id");
    var form = document.getElementById(formId);
    var projects = this.getAllProjects();
    for (var a = 0; a < projects.length; a++) {

        // if project matches
        if (projects[a].id == form.project.value) {

            // loop through all tasks of that project
            for (var b = 0; b < projects[a].tasks.length; b++) {

                // if task matches
                if (projects[a].tasks[b].id == form.task.value) {

                    // if the status is set to delete
                    if (self.value == "delete") {

                        // ask for confirmation
                        swal({
                            title: "Are you sure?",
                            text: "Deleting the task will delete its hours too.",
                            icon: "warning",
                            buttons: true,
                            dangerMode: true,
                        })
                        .then((willDelete) => {
                            if (willDelete) {

                                // remove task from array
                                projects[a].tasks.splice(b, 1);

                                // update local storage
                                localStorage.setItem(this.key, JSON.stringify(projects));

                                // re-load all tasks
                                this.showAllTasks();
                            } else {

                                // reset dropdown
                                self.value = "";
                            }
                        });
                    } else if (self.value == "complete") {
                        // mark as completed
                        projects[a].tasks[b].status = "Completed";

                        // stop the timer
                        projects[a].tasks[b].isStarted = false;

                        // log end time
                        projects[a].tasks[b].ended = this.getCurrentTimeInTaskStartEndFormat();
                        for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                            if (projects[a].tasks[b].logs[c].endTime == 0) {
                                projects[a].tasks[b].logs[c].endTime = new Date().getTime();
                                break;
                            }
                        }
                    } else if (self.value == "progress") {
                        // mark as in progress
                        projects[a].tasks[b].status = "Progress";

                        // stop the timer
                        projects[a].tasks[b].isStarted = false;
                    } else if (self.value == "start") {
                        // ask for confirmation
                        swal({
                            title: "Are you sure?",
                            text: "This will start the timer.",
                            icon: "warning",
                            buttons: true,
                            dangerMode: true,
                        })
                        .then((doStart) => {
                            if (doStart) {
                                
                                // mark as started
                                projects[a].tasks[b].isStarted = true;

                                // add in log
                                var logObj = {
                                    id: projects[a].tasks[b].logs.length,
                                    startTime: new Date().getTime(),
                                    endTime: 0
                                };
                                projects[a].tasks[b].logs.push(logObj);

                                // update local storage
                                localStorage.setItem(this.key, JSON.stringify(projects));

                                // re-load all tasks
                                this.showAllTasks();
                            } else {

                                // reset dropdown
                                self.value = "";
                            }
                        });
                    } else if (self.value == "stop") {

                        // ask for confirmation
                        swal({
                            title: "Are you sure?",
                            text: "This will stop the timer.",
                            icon: "warning",
                            buttons: true,
                            dangerMode: true,
                        })
                        .then((doStop) => {
                            if (doStop) {

                                // mark as stopped
                                projects[a].tasks[b].isStarted = false;

                                // update end time in log
                                for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                                    if (projects[a].tasks[b].logs[c].endTime == 0) {
                                        projects[a].tasks[b].logs[c].endTime = new Date().getTime();
                                        break;
                                    }
                                }

                                // update local storage
                                localStorage.setItem(this.key, JSON.stringify(projects));

                                // re-load tasks
                                this.showAllTasks();
                            } else {

                                // reset dropdown
                                self.value = "";
                            }
                        });
                    }
                    break;
                }
            }
            break;
        }
    }

    // delete, start and stop are already handled above
    if (self.value == "delete"
        || self.value == "start"
        || self.value == "stop") {
        //
    } else {
        // update local storage and re-load tasks
        localStorage.setItem(this.key, JSON.stringify(projects));
        this.showAllTasks();
    }
},

Comments have been added with each line for an explanation. If you still find it difficult, please feel free to mention it in the comments section below.

At this point, you will be able to start and stop the timer. Upon stopping, you will be able to see the start and end time of the task along with the total duration of the task.

Now, we need to update the timer each second if the task is started. You need to write the following lines in your window “load” event listener:

// call this function each second
setInterval(function () {

    // increment 1 second in all running tasks
    var dataStarted = document.querySelectorAll("td[data-started]");
    for (var i = 0; i < dataStarted.length; i++) {
        var dataStartedObj = dataStarted[i].getAttribute("data-started");
        var dataStartedObj = JSON.parse(dataStartedObj);
        dataStartedObj.duration++;

        // convert timestamp into readable format
        var hours = Math.floor(dataStartedObj.duration / 3600) % 24;
        hours = (hours < 10) ? "0" + hours : hours;
        // var days = Math.floor(diff / 86400);
        var minutes = Math.floor(dataStartedObj.duration / 60) % 60;
        minutes = (minutes < 10) ? "0" + minutes : minutes;
        var seconds = dataStartedObj.duration % 60;
        seconds = (seconds < 10) ? "0" + seconds : seconds;
        dataStarted[i].innerHTML = hours + ":" + minutes + ":" + seconds;

        // update log end time
        var projects = taskObj.getAllProjects();
        for (var a = 0; a < projects.length; a++) {
            if (projects[a].id == dataStartedObj.project) {
                for (var b = 0; b < projects[a].tasks.length; b++) {
                    if (projects[a].tasks[b].id == dataStartedObj.task) {
                        for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                            if (c == projects[a].tasks[b].logs.length - 1) {
                                projects[a].tasks[b].logs[c].endTime = new Date().getTime();

                                // update local storage
                                window.localStorage.setItem(taskObj.key, JSON.stringify(projects));

                                // update timer
                                dataStarted[i].setAttribute("data-started", JSON.stringify(dataStartedObj));

                                break;
                            }
                        }
                        break;
                    }
                }
                break;
            }
        }
    }
}, 1000);

For explanation, comments have been added. Feel free to ask if you are having trouble understanding something.

Delete project

You are now able to create projects, now is the time to have the ability to delete them. So create a simple form that displays a list of all created projects in a dropdown:

<!-- form to delete project -->
<form method="POST" onsubmit="return taskObj.deleteProject(this);" style="display: contents;">
    <select name="project" class="form-control" style="display: initial; width: 200px; margin-left: 5px; margin-right: 5px;" id="form-task-hour-calculator-all-projects"></select>
    <input type="submit" class="btn btn-danger" value="Delete Project">
</form>

Then we need to create a function “deleteProject” in our “taskObj” object that will delete the project from local storage and refresh the projects and tasks UI.

// delete project
deleteProject: function (self) {

    // check if any project is selected
    if (self.project.value == "") {
        swal("Please select a project to delete");
        return false;
    }

    // ask for confirmation
    swal({
        title: "Are you sure?",
        text: "Deleting the project will delete its tasks too.",
        icon: "warning",
        buttons: true,
        dangerMode: true,
    })
    .then((willDelete) => {
        if (willDelete) {

            // remove from array and update local storage
            var projects = taskObj.getAllProjects();
            for (var a = 0; a < projects.length; a++) {
                if (projects[a].id == self.project.value) {
                    projects.splice(a, 1);
                    localStorage.setItem(taskObj.key, JSON.stringify(projects));

                    // re-load data
                    taskObj.loadAllProjects();
                    taskObj.showAllTasks();

                    break;
                }
            }
        } else {

            // reset project dropdown
            self.project.value = "";
        }
    });
    return false;
}

Applying CSS Styles

This may not be the major concern for you, but just to highlight the task when it is started and when it is completed, we are applying some CSS styles to it.

/* style when project is started */
.started {
    color: white;
    font-weight: bold;
    background: green;
    padding: 5px;
    border-radius: 5px;
}

/* style when project is completed */
.completed {
    color: white;
    font-weight: bold;
    background: greenyellow;
    padding: 5px;
    border-radius: 5px;
}

Congratulations ! You just created your own task management and time tracking script in Javascript. Feel free to add more features in it as per your needs.

[wpdm_package id=’1219′]

PHP object as argument to Javascript function

Suppose you have a PHP variable or an object which you want to pass as an argument to a Javascript function whenever a button is clicked. Following this tutorial, you will be able to do so.

We will not be directly sending the PHP variable, but instead, we will attach the PHP variable to the HTML tag attribute and then send that tag to the Javascript function.

<?php
    $variable = "Adnan";

    $object = new \stdClass();
    $object->my_value = 2021;
?>

<button type="button"
    data-variable="<?php echo $variable; ?>"
    data-object="<?php echo htmlentities(json_encode($object)); ?>"
    onclick="buttonClicked(this);">Button</button>

<script>
    function buttonClicked(self) {
        var variable = self.getAttribute("data-variable");
        console.log(variable);

        var object = self.getAttribute("data-object");
        object = JSON.parse(object);
        console.log(object.my_value);
    }
</script>

When the button is clicked, we are sending a PHP object to the Javascript function as an argument. We are also sending a complete PHP object too. PHP objects can be sent by first converting them into JSON string format. You can learn more about the htmlentities function from PHP official documentation. Then we will convert the JSON string characters into HTML entities.

And on the Javascript side, we simply have to parse the JSON string back into a Javascript array or object. If you face any problems implementing this in your project, please let us know in the comments section.

You can also check our more tutorials on PHP.

[wpdm_package id=’1217′]

Count extended fingers – Leap Motion Controller + Javascript

In this tutorial, we are going to show you can count extended fingers of your hand using Leap and Javascript. Extended fingers mean your stretched or opened fingers. If you prefer a video tutorial, you can check our video tutorial on YouTube.

Leap Motion Controller is a device used to detect hand motions and gestures. It came with a software development kit (SDK) for different languages i.e. C++, C#, Python, Javascript, Java, Unity, and Unreal Engine. You can buy Leap Motion Controller from here. You can get all the languages SDK from this link.

Video tutorial

We are going to show different images based on extended fingers. If you have downloaded the Javascript SDK then you will find a file named “leap-0.6.4.min.js” in it. You need to copy that file in your project. We have created a folder named “images”. In this folder, we have placed 3 images named “1.jpg”, “2.jpg” and “3.jpg”.

We will be using “index.php” file as the main file. The following code will show images based on your hand’s extended fingers.

<script src="leap-0.6.4.min.js"></script>

<img id="image" style="display: none;" />

<script>
    // Setup Leap loop with frame callback function
    var controllerOptions = {};

    Leap.loop(controllerOptions, function(frame) {
        // Body of callback function
        var hands = frame.hands;
        if (hands.length > 0) {

            var hand = hands[0];

            var extendedFingers = 0;
            for(var f = 0; f < hand.fingers.length; f++){
                var finger = hand.fingers[f];
                if(finger.extended) {
                    extendedFingers++;
                }
            }

            if (extendedFingers > 0 && extendedFingers <= 3) {
                document.getElementById("image").setAttribute("src", "images/" + extendedFingers + ".jpg");
                document.getElementById("image").style.display = "";
            } else {
                document.getElementById("image").style.display = "none";
            }
        }
    });
</script>

<style>
    #image {
        width: 100%;
        height: 100%;
        object-fit: contain;
    }
</style>

Explanation

  1. First we have included Leap JS SDK.
  2. Then we created an empty image tag and hide it.
  3. Leap.loop function will be called on each frame.
  4. On each frame, we are checking if there is any hand on top of Leap.
  5. If there is, then we are counting extended fingers.
  6. If there are more than zero and less than 4 extended fingers, then we are rendering image and displaying it.
  7. Otherwise, we are hiding the image.
  8. CSS styles are applied to fit the image inside the browser window.

Move your hand on top of your Leap Motion Controller and try to extend your fingers one-by-one. You will see the images will be changed as per the number of fingers extended. That’s how you can count extended fingers on your hand in Leap Motion Controller.

Check out our more tutorials on Leap Motion Controller.

[wpdm_package id=’1213′]

Verify email with code – PHP & MySQL

In this tutorial, we will learn how to verify email with code. When someone registers on your website, send him/her an email with a verification code and show a form to enter the code on your website. The user must enter the verification code in that form to verify his email. Only verified users will be allowed to log in.

Create users table

First, you need to create a “users” table in your database. Your table must have a “verification_code” field that will hold the code sent in the email. And the “email_verified_at” field tells the time the email was verified. This field will also be used to check if the user has verified his email or not.

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` text NOT NULL,
  `email` text NOT NULL,
  `password` text NOT NULL,
  `verification_code` text NOT NULL,
  `email_verified_at` datetime DEFAULT NULL
);

User registration

Usually, the registration form has a name, email, and password field for the user.

<form method="POST">
    <input type="text" name="name" placeholder="Enter name" required />
    <input type="email" name="email" placeholder="Enter email" required />
    <input type="password" name="password" placeholder="Enter password" required />

    <input type="submit" name="register" value="Register">
</form>

When this form submits, we need to generate a verification code and send it to the user. To send an email, we are going to use a library called “PHPMailer”. Make sure you have “composer” downloaded and installed in your system. Run the following command at the root of your project:

composer require phpmailer/phpmailer

You can also download and include the PHPMailer library manually from Github. The following code will send a verification code to the user’s email address and save the user’s data in the database:

<?php
    //Import PHPMailer classes into the global namespace
    //These must be at the top of your script, not inside a function
    use PHPMailer\PHPMailer\PHPMailer;
    use PHPMailer\PHPMailer\SMTP;
    use PHPMailer\PHPMailer\Exception;

    //Load Composer's autoloader
    require 'vendor/autoload.php';

    if (isset($_POST["register"]))
    {
        $name = $_POST["name"];
        $email = $_POST["email"];
        $password = $_POST["password"];

        //Instantiation and passing `true` enables exceptions
        $mail = new PHPMailer(true);

        try {
            //Enable verbose debug output
            $mail->SMTPDebug = 0;//SMTP::DEBUG_SERVER;

            //Send using SMTP
            $mail->isSMTP();

            //Set the SMTP server to send through
            $mail->Host = 'smtp.gmail.com';

            //Enable SMTP authentication
            $mail->SMTPAuth = true;

            //SMTP username
            $mail->Username = 'your_email@gmail.com';

            //SMTP password
            $mail->Password = 'your_password';

            //Enable TLS encryption;
            $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;

            //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
            $mail->Port = 587;

            //Recipients
            $mail->setFrom('your_email@gmail.com', 'your_website_name');

            //Add a recipient
            $mail->addAddress($email, $name);

            //Set email format to HTML
            $mail->isHTML(true);

            $verification_code = substr(number_format(time() * rand(), 0, '', ''), 0, 6);

            $mail->Subject = 'Email verification';
            $mail->Body    = '<p>Your verification code is: <b style="font-size: 30px;">' . $verification_code . '</b></p>';

            $mail->send();
            // echo 'Message has been sent';

            $encrypted_password = password_hash($password, PASSWORD_DEFAULT);

            // connect with database
            $conn = mysqli_connect("localhost:8889", "root", "root", "test");

            // insert in users table
            $sql = "INSERT INTO users(name, email, password, verification_code, email_verified_at) VALUES ('" . $name . "', '" . $email . "', '" . $encrypted_password . "', '" . $verification_code . "', NULL)";
            mysqli_query($conn, $sql);

            header("Location: email-verification.php?email=" . $email);
            exit();
        } catch (Exception $e) {
            echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
        }
    }
?>

User login

When users try to log in, we must check if the user’s email is verified or not. Usually, login form has 2 fields, email, and password:

<form method="POST">
    <input type="email" name="email" placeholder="Enter email" required />
    <input type="password" name="password" placeholder="Enter password" required />

    <input type="submit" name="login" value="Login">
</form>

When this form submits, we will check if the user’s credentials are okay. And also if his/her email is verified.

<?php
    
    if (isset($_POST["login"]))
    {
        $email = $_POST["email"];
        $password = $_POST["password"];

        // connect with database
        $conn = mysqli_connect("localhost:8889", "root", "root", "test");

        // check if credentials are okay, and email is verified
        $sql = "SELECT * FROM users WHERE email = '" . $email . "'";
        $result = mysqli_query($conn, $sql);

        if (mysqli_num_rows($result) == 0)
        {
            die("Email not found.");
        }

        $user = mysqli_fetch_object($result);

        if (!password_verify($password, $user->password))
        {
            die("Password is not correct");
        }

        if ($user->email_verified_at == null)
        {
            die("Please verify your email <a href='email-verification.php?email=" . $email . "'>from here</a>");
        }

        echo "<p>Your login logic here</p>";
        exit();
    }
?>

Email verification

Create a file named “email-verification.php” and create a hidden input field for email and a text field for verification code:

<form method="POST">
    <input type="hidden" name="email" value="<?php echo $_GET['email']; ?>" required>
    <input type="text" name="verification_code" placeholder="Enter verification code" required />

    <input type="submit" name="verify_email" value="Verify Email">
</form>

When this form submits, we will check if the verification code matches the one in the database. If the code does not match then it will show an error, otherwise, it will mark the user as verified.

<?php

    if (isset($_POST["verify_email"]))
    {
        $email = $_POST["email"];
        $verification_code = $_POST["verification_code"];

        // connect with database
        $conn = mysqli_connect("localhost:8889", "root", "root", "test");

        // mark email as verified
        $sql = "UPDATE users SET email_verified_at = NOW() WHERE email = '" . $email . "' AND verification_code = '" . $verification_code . "'";
        $result  = mysqli_query($conn, $sql);

        if (mysqli_affected_rows($conn) == 0)
        {
            die("Verification code failed.");
        }

        echo "<p>You can login now.</p>";
        exit();
    }

?>

Conclusion

Adding this feature to your website helps you to separate real and fake email addresses in your database. It will greatly help you in your marketing and you will be satisfied that your emails are going to real email accounts. If you want to know if your email is being read by the receiver or not, please follow this.

Convert date format to another – PHP, HTML

In this tutorial, we are going to teach you how to convert the date format from one to another using Javascript. We will also be adding, subtracting date by days.

Video tutorial

First, we will create a form to get the source and destination format from the user.

<form method="POST" onsubmit="return generateCode(this);">
    
    <div>
        <select name="source_format">
            <option value="">Enter source format</option>
            <option value="timestamp">Timestamp (123456789)</option>
            <option value="Y-m-d">Y-m-d (2020-08-30)</option>
            <option value="Y-m-d H:i:s">Y-m-d H:i:s (2020-08-30 14:30:18)</option>
            <option value="Y-m-d h:i:s A">Y-m-d h:i:s A (2020-08-30 02:30:18 PM)</option>
            <option value="Y-m-d h:i:s a">Y-m-d h:i:s a (2020-08-30 02:30:18 pm)</option>
            <option value="d M, Y">d M, Y (30 August, 2020)</option>
            <option value="D">D (Mon, Tue)</option>
        </select>
    </div>

    <div style="margin-top: 10px;">
        <select name="destination_format">
            <option value="">Enter destination format</option>
            <option value="timestamp">Timestamp (123456789)</option>
            <option value="Y-m-d">Y-m-d (2020-08-30)</option>
            <option value="Y-m-d H:i:s">Y-m-d H:i:s (2020-08-30 14:30:18)</option>
            <option value="Y-m-d h:i:s A">Y-m-d h:i:s A (2020-08-30 02:30:18 PM)</option>
            <option value="Y-m-d h:i:s a">Y-m-d h:i:s a (2020-08-30 02:30:18 pm)</option>
            <option value="d M, Y">d M, Y (30 August, 2020)</option>
            <option value="D">D (Mon, Tue)</option>
        </select>
    </div>

    <input type="submit" value="Generate Code" />

    <p id="output" style="display: none;"></p>
</form>

Then we will create a Javascript function that will write the PHP code to echo the date by converting it from source format to destination format.

<script>
    function generateCode(form) {

        var sourceFormat = form.source_format.value;
        var destinationFormat = form.destination_format.value;

        var html = "";
        var dateHtml = "";
        if (sourceFormat == "timestamp" && destinationFormat == "timestamp") {
            dateHtml = `echo $timestamp_value;`;
        } else if (sourceFormat == "timestamp") {
            dateHtml = `echo date('` + destinationFormat + `', $timestamp_value);`;
        } else if (destinationFormat == "timestamp") {
            dateHtml = `echo strtotime($date_value);`;
        } else {
            dateHtml = `echo date('` + destinationFormat + `', strtotime($date_value));`;
        }
        html += `&lt;?php<br />
            <span style='margin-left: 1em;'>&emsp;` + dateHtml + `</span><br />
        ?>`;
        
        document.getElementById("output").innerHTML = html;
        document.getElementById("output").style.display = '';

        return false;
    }
</script>

The resulting output will be displayed in a paragraph. Right now we are displaying a dropdown to select a date format. But what if the user wants to write a custom format ? So we will create 2 more fields for writing custom format for source and destination.

<input type="text" style="margin-left: 10px;" name="source_format_custom" placeholder="Custom source format" />

<input type="text" style="margin-left: 10px;" name="destination_format_custom" placeholder="Custom destination format" />

Then we need to update our custom date format variables if these fields have some value.

var sourceFormat_custom = form.source_format_custom.value;
if (sourceFormat_custom != "") {
    sourceFormat = sourceFormat_custom;
}

var destinationFormat_custom = form.destination_format_custom.value;
if (destinationFormat_custom != "") {
    destinationFormat = destinationFormat_custom;
}

Add/subtract from the date

Now we need to add or subtract months, years, or days from the new date format. For this, we will create 2 dropdowns to check if the user wants to add or subtract. And second to check if he wants to add/subtract days, months, or years.

<p style="text-align: center;">Add / subtract date (optional)</p>

<div>
    <select name="addsubtract_date">
        <option value="">None</option>
        <option value="add">Add</option>
        <option value="subtract">Subtract</option>
    </select>

    <select name="addsubtract_datetype">
        <option value="years">Years</option>
        <option value="months">Months</option>
        <option value="days">Days</option>
        <option value="hours">Hours</option>
        <option value="minutes">Minutes</option>
        <option value="seconds">Seconds</option>
    </select>
</div>

<input type="number" placeholder="Enter value" name="addsubtract_datevalue" />

Now when the form is submitted, we need to get the values of both these dropdowns.

var addsubtractdate = "";
if (form.addsubtract_date.value == "add") {
    addsubtractdate = "'+ " + form.addsubtract_datevalue.value + " " + form.addsubtract_datetype.value + "'";
} else if (form.addsubtract_date.value == "subtract") {
    addsubtractdate = "'- " + form.addsubtract_datevalue.value + " " + form.addsubtract_datetype.value + "'";
}

After that, we need to make changes in every echo statement in our Javascript code to handle this add/subtract feature.

if (sourceFormat == "timestamp" && destinationFormat == "timestamp") {
    if (addsubtractdate == "") {
        dateHtml = `echo $timestamp_value;`;
    } else {
        dateHtml = `echo strtotime(` + addsubtractdate + `, $timestamp_value);`;
    }
} else if (sourceFormat == "timestamp") {
    if (addsubtractdate == "") {
        dateHtml = `echo date('` + destinationFormat + `', $timestamp_value);`;
    } else {
        dateHtml = `echo date('` + destinationFormat + `', strtotime(` + addsubtractdate + `, $timestamp_value));`;
    }
} else if (destinationFormat == "timestamp") {
    if (addsubtractdate == "") {
        dateHtml = `echo strtotime($date_value);`;
    } else {
        dateHtml = `echo strtotime(` + addsubtractdate + `, strtotime($date_value));`;
    }
} else {
    if (addsubtractdate == "") {
        dateHtml = `echo date('` + destinationFormat + `', strtotime($date_value));`;
    } else {
        dateHtml = `echo date('` + destinationFormat + `', strtotime($date_value . ` + addsubtractdate + `));`;
    }
}

You can run the script now, and you will be able to generate the code for converting the date from one format to another. Moreover, you can also get the code for adding/subtracting days, months, or years from the resultant date. That’s how you can convert date format from one to another.

Learn how to calculate the time passed since the date in PHP and Javascript.

Calculate time passed since date – Javascript, PHP

Feel free to download the source code below.

[wpdm_package id=’1183′]

Prevent file access from URL – PHP htaccess

When developing a web application, it is very important for you to prevent file access from URL for the users. Because someone might try to download all your images and videos by directly accessing them from the URL. You must allow users to view the images and videos directly from your website instead of just letting the automated scripts download all uploaded data.

.htaccess

First, you need to create a file named “.htaccess” along with the dot “.” without the double quotes at the root folder of your project. Some operating systems hide the files that start with a dot extension.

  • In Windows, go to “view” from the top menu and check the “show hidden items” checkbox.
  • In Mac, press (command + shift + dot) (⌘ + ⇧ + .) at the same time.
  • In Ubuntu, press Ctrl + H.

Following should be the content of your .htaccess file:

# enable mod_rewrite
RewriteEngine On

# RewriteCond = define rule condition
# HTTP_REFERER = check from where the request originated
# ! = exclude
# ^ = start of string
# [NC] = case insensitive search
RewriteCond %{HTTP_REFERER} !^http://localhost:8888/tutorials/video-streaming-php [NC]

# \ = match any
# . = any character
# () = pattern, group
# $ = end of string

# [F] = forbidden, 403
# [L] = stop processing further rules
RewriteRule \.(gif|jpg|jpeg|png|mp4|mov|mkv|flv)$ - [F,L]

At line #9, you must place your website base URL without forwarding the slash “/” at the end. Using htaccess, you can also prevent “.env” files from accessing in your Laravel application. Follow this for more.

Access from code only

Now if you try to access the file directly from the URL, you will get a 403 Forbidden error. But you can easily access it from your code like this:

<video src="video.mp4" controls></video>

This prevent file access from the URL but you can still see it in the browser. However, the user can still manually download the video file. But it prevents the automated scripts to download all the files from your server directory.

Detect multiple tabs opened at the same time – Javascript

If you have used WhatsApp Web, you may encounter a situation where if you open the web.whatsapp.com in multiple tabs in the same browser, you will get the error that “it is already being opened in another tab”. So in this article, we are going to teach you how you can detect multiple tabs opened at the same time using vanilla Javascript.

This is done for various reasons, top of the most is security. So how you can add this feature to your website ? The following code will display an alert message if a 2nd tab is opened at the same time:

<script>
    // Broadcast that you're opening a page.
    localStorage.openpages = Date.now();
    window.addEventListener('storage', function (e) {
        if(e.key == "openpages") {
            // Listen if anybody else is opening the same page!
            localStorage.page_available = Date.now();
        }
        if(e.key == "page_available") {
            alert("One more page already open");
        }
    }, false);
</script>

window.addEventListener(‘storage’, function (e) {});” This listener will be called only when the local storage value is updated from an external source, which means the other tab has made any changes in the local storage.

[do_widget id=custom_html-4]

How it works:

You might need to read the following steps 2 or 3 times to grab the concept properly.

  1. When you open the 1st tab, line # 3 will create a local storage value named “openpages”.
  2. Storage listener will NOT be called because the local storage value is updated from this tab.
  3. When you open the second tab, line # 3 will also create a local storage value named “openpages”.
  4. Storage listener from the 1st tab will be called because the local storage is updated from the 2nd tab.
  5. 1st tab will receive the value of “e.key” as “openpages”.
  6. So it will create another local storage value “page_available” at line # 7.
  7. Now this will call the storage listener from the 2nd tab. Because for the 2nd tab, it is called from the 1st tab.
  8. 2nd tab will receive the value of “e.key” as “page_available”, so it will display an alert message.

That’s how you can detect multiple tabs opened by the user at the same time. Let me know if you have any problem understanding this.