ToDo App in PHP with authentication

This tutorial is going to be an exciting and thrilling one as we are going to create a simple ToDo App in PHP with authentication with an actual database. We are also going to use bootstrap for the front end and jquery in some parts as well. Also, we are going to implement the feature of login and signup for the users. We are going to use MySQL database for database and PHP for the backend. Also, we will, later on, add the feature to add, view, and delete to-do items.

Note: The to-do for all the users will be private to them only.

We will also learn to use md5 hashing for the passwords to make our web app more secure.

Output for ToDo App in PHP:

Before we start building ToDo App in PHP, let’s first have a look at what we are actually going to develop.

Video output:

Image output:

output for ToDo App in PHP with authentication

Download the full project resources:

Requirements

  • Xampp
  • Text editor (Vs code, Sublime text, Atom)
  • Browser (Chrome, Firefox, Edge, Opera)
  • Basic knowledge of HTML, CSS, PHP, MySQL, and jquery

Features

  • Login
  • Signup
  • Add todo
  • View todo
  • Delete todo
  • Logout

Note: The to-do for all the users will be private to them only.

Project setup

Xampp setup

Note if you don’t have xampp installed, follow this link to install xampp. Before jumping right into code make sure that you have Xampp installed and these 2 important processes running Apache and MySQL.

run apache and MySQL in xampp

Project folder structure

folder structure

Coding ToDo App in PHP with authentication

We will do all the code in the c/Xampp/htdocs folder. We will create a new folder with the name todoPhp and open it in the text editor. So first we will draw the simple form for the login and signup and pass the parameters to a function that will later process with PHP.

index.php

The code for the form will be something like this and it will be in the index.php file

<!-- Login Form -->
<div class="container">
        <div class="row">
            <div class="col-md-6 offset-md-3 formcontainer">
                <h1 class="d-flex justify-content-center mt-5">LOGIN FORM</h1>
                <form method="post" action="assets/backend/auth.php" class="border rounded p-4 border-primary login-form">
                    <div class="mb-3">
                        <label for="login_email" class="form-label">Email address</label>
                        <input type="email" class="form-control" id="login_email" name="login_email" required>
                    </div>
                    <div class="mb-3">
                        <label for="login_password" class="form-label">Password</label>
                        <input type="password" class="form-control" id="login_password" name="login_password" required>
                    </div>
                    <button type="submit" name="login-btn" id="login-btn" class="btn btn-primary">Login</button>
                </form>
 
                <div class="d-flex justify-content-end">
                    <a href="">Forget Password</a>
                </div>
                <div class="d-flex justify-content-center">
                    Don't have an account ?? <a href="register.php"> Sign Up</a>
                </div>
            </div>
        </div>
    </div>
    <!-- ./Login Form -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

register.php

Also, we will now create the registered user page and the code for the form will be something like this and it will be in the register.php file.

<div class="container">
        <div class="row">
            <div class="col-md-6 offset-md-3 formcontainer ">
                <h1 class="d-flex justify-content-center mt-5">SIGNUP FORM</h1>
 
                <form method="post" action="assets/backend/auth.php" class="border rounded p-4 border-primary login-form">
                    <div class="mb-3">
                        <label for="username" class="form-label">Username</label>
                        <input type="text" class="form-control" id="username" name="username" placeholder="Enter name" required>
                    </div>
                    <div class="mb-3">
                        <label for="email" class="form-label">Email address</label>
                        <input type="email" class="form-control" id="email" name="email" placeholder="Enter email" required>
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">Password</label>
                        <input type="password" class="form-control" id="password" name="password" placeholder="Enter password" required>
                    </div>
                    <div class="mb-3">
                        <label for="c_password" class="form-label">Confirm Password</label>
                        <input type="text" class="form-control" id="c_password" name="c_password" placeholder="Confirm Password" required>
                    </div>
                    <button type="submit" id="signup-btn" name="signup-btn" class="btn btn-primary d-flex justify-content-center">Sign Up</button>
                </form>
                <div class="d-flex justify-content-center">
                    Already have an account ?? <a href="index.php"> Login</a>
                </div>
            </div>
        </div>
    </div>
    <!-- ./Signup Form -->
 
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

Database for project

Before we go into more detail, we will first create the database and the table for the users and the to-do items.

To create the required tables for ToDo App in PHP, we will add a new database by the name todophp in the PHPMyAdmin, and then we will import the SQL file that is given in the resources.

So, first, we will create the database and the table for the users and the to-do items.

Steps to create new database and tables:

1. First, visit http://localhost/phpmyadmin/ in your browser.

2. Click on the new icon on the left.

click on new

3. After that, fill in the text box with todophp and hit create button.

click on create

4. After that go to the import button and select the file and click the import button on the bottom.

click import
click import given below

If successful you will see a screen something like this 

output of import

todophp.sql

This is the file to import.

-- phpMyAdmin SQL Dump
-- version 5.2.0
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Generation Time: Dec 04, 2022 at 12:57 PM
-- Server version: 10.4.27-MariaDB
-- PHP Version: 7.4.33
 
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
 
 
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
 
--
-- Database: `todophp`
--
 
-- --------------------------------------------------------
 
--
-- Table structure for table `todolist`
--
 
CREATE TABLE `todolist` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `tasks` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
  `updated_at` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 
-- --------------------------------------------------------
 
--
-- Table structure for table `users`
--
 
CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `username` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `status` int(11) NOT NULL DEFAULT 1,
  `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
  `updated_at` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 
--
-- Indexes for dumped tables
--
 
--
-- Indexes for table `todolist`
--
ALTER TABLE `todolist`
  ADD PRIMARY KEY (`id`),
  ADD KEY `user_id` (`user_id`);
 
--
-- Indexes for table `users`
--
ALTER TABLE `users`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `email` (`email`);
 
--
-- AUTO_INCREMENT for dumped tables
--
 
--
-- AUTO_INCREMENT for table `todolist`
--
ALTER TABLE `todolist`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14;
 
--
-- AUTO_INCREMENT for table `users`
--
ALTER TABLE `users`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
 
--
-- Constraints for dumped tables
--
 
--
-- Constraints for table `todolist`
--
ALTER TABLE `todolist`
  ADD CONSTRAINT `todolist_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);
COMMIT;
 
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

After we have run the queries the tables for users and todos will be created.

db_connection.php

In the assets/backend folder, we will create a db_connection.php file to connect to our database of ToDo App in PHP.

<?php
// database Connection
$hostname = "localhost";
$username = "root";
$password = "";
$db =  "todophp";
$conn = new mysqli($hostname,$username,$password,$db);
if($conn->connect_error){
die("connection error".$conn->connect_error);
}
session_start();
error_reporting('1');
?>
 
<!--Now in the assets/backend folder-->
<!--We will define the logic for login and register in our auth.php file-->
 
<?php
    include 'db_connection.php';
    // ========== LOGIN USERS ==========
    $login_email = $_POST['login_email'];
    $login_password = md5($_POST['login_password']);
    if(isset($_POST['login-btn'])){
        if(filter_var($login_email, FILTER_VALIDATE_EMAIL)){
            $select = "SELECT * FROM `users` WHERE email = '$login_email'";
            $query = mysqli_query($conn, $select);
            $row = mysqli_fetch_assoc($query);
            if($row){
                if($row['password'] == $login_password){
                    $_SESSION['username'] = $row['username'];
                    $_SESSION['user_id'] = $row['id'];
                    $_SESSION['email'] = $row['email'];
                    $_SESSION['status'] = $row['status'];
                    $_SESSION['logged_in'] = true;
 
                    header("location:http://localhost/todoPhp/home.php?username=$row[username]");
                }else{
                    echo "<script>alert('Wrong Password...try again!!'); window.location='../../index.php';</script>";
                }
            }else{
                echo "<script>alert('User does not exist...try again!!'); window.location='../../index.php';</script>";
            }
        }else{
            echo "<script>alert('Invalid email...Enter a valid email!!'); window.location='../../index.php';</script>";
        }
    }
 
    // ========== SIGNUP USERS ==========
    $username = $_POST['username'];
    $email = $_POST['email'];
    $password = $_POST['password'];
    $c_password = $_POST['c_password'];
 
    if(isset($_POST['signup-btn'])){
        if(filter_var($email, FILTER_VALIDATE_EMAIL)){
            if($password == $c_password){
                $select = "SELECT * FROM `users` WHERE email = '$email'";
                $query = mysqli_query($conn, $select);
                $row = mysqli_fetch_assoc($query);
                if(!$row){
                    $insert = "INSERT INTO `users`(`username`, `email`, `password`, `created_at`, `updated_at`) VALUES ('$username','$email',md5($password),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)";
                    $query = mysqli_query($conn,$insert);
                    if($query){
                        echo "<script>alert('Your account has been created successfully!!'); window.location='../../index.php';</script>";  
                    }else{
                        echo "<script>alert('Something went wrong...try again!!'); window.location='../../register.php';</script>";  
                    }
                }else{
                    echo "<script>alert('User already exists...try again!!'); window.location='../../register.php';</script>";  
                }
 
            }else{
                echo "<script>alert('Password and Confirm Password does not match...try again!!'); window.location='../../register.php';</script>";  
            }
        }else{
            echo "<script>alert('Invalid email...Enter a valid email!!'); window.location='../../register.php';</script>";
        }
    }
?>

Hashing the password

Here, instead of storing the normal password, we store the md5 hashed password in the database so that the password is not stored in plain text in the database.

We do that by this function in PHP

$hashedPassword = md5($password);

Also during login, we check the md5 hashed password with the md5 hashed password in the database, thus ensuring that the passwords are not compromised.

To add the logout functionality we add this line in the logout.php file which is in assets/backend/logout.php.

<?php
session_start();
session_destroy();
header("location:http://localhost/todoPhp/index.php?msg=logout");
?>

To add all the UI for the todo’s we do add these lines in our home.php file.

<?php
    include 'assets/backend/db_connection.php';
    if($_SESSION['logged_in'] == true){  
    include 'assets/backend/todo.php';
 
?>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Todo App</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
    <link rel="stylesheet" href="assets/css/style.css">
  </head>
  <body>
        <!-- Navbar -->
        <nav class="navbar bg-light">
            <div class="container">
                <span class="navbar-brand mb-0 h1"><?php echo $_SESSION['username'];?></span>
                <div class="d-flex justify-content-end logout-btn"><a href="assets/backend/logout.php">Logout</a></div>
            </div>
        </nav>
        <!-- ./Navbar -->
 
        <!-- Todo section  -->
        <div class="container">
            <div class="row">
                <div class="col-md-6 offset-md-3">
                    <!-- add todo -->
                            <div id="add-btn" class=" d-flex justify-content-center mt-5">
                                    <span  class="btn btn-primary"><i class="fa-solid fa-plus"></i> Add Todo</span>    
                            </div>
                            <div id="add-todo-form" class="mt-5">
                                <form action="assets/backend/todo.php" method="post" >
                                    <div class="input-group mb-3">
                                        <input type="text" class="form-control" id="add-todo" name="add-todo" placeholder="Enter your todo here"  >
                                        <button class="btn btn-primary" name="add-todo-btn" id="add-todo-btn" type="submit">Add</button>
                                    </div>
                                </form>
                            </div>
                    <!-- ./add todo -->
 
                    <!-- todo table -->
                    <table class="table border rounded mt-5" >
                        <thead>
                            <tr>
                            <th scope="col">#</th>
                            <th class="text-center" scope="col">Tasks</th>
                            <th class="text-center" scope="col">
                                Actions
                            </th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php $sno = 1; while($row = mysqli_fetch_assoc($s_query)){?>
                                <tr>
                                <th scope="row" ><?php echo $sno++;?></th>
                                <td class="text-center">
                                    <div class="task-list">
                                        <?php echo $row['tasks'];?>
                                    </div>
                                </td>
                                <td class="text-center">
                                    <form action="assets/backend/todo.php?id=<?php echo $row['id'];?>" method="post">
                                        <button class="btn btn-danger" name="dlt-todo-btn" id="dlt-todo-btn" type="submit">Delete</button>
                                    </form>
                                </td>
                                </tr>
                            <?php }?>
                           
                        </tbody>
                    </table>
                    <!-- ./todo table -->
                </div>
            </div>
        </div>
        <!-- ./Todo section  -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/js/all.min.js" integrity="sha512-rpLlll167T5LJHwp0waJCh3ZRf7pO6IT1+LZOhAyP6phAirwchClbTZV3iqL3BMrVxIYRbzGTpli4rfxsCK6Vw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
   
    <script>
        $(document).ready(function(){
            $( "#add-btn" ).click(function() {
                    $("#add-todo-form").toggle();  
            });
        });
    </script>
  </body>
</html>
// To take care of if the user tries to access the home.php page without logging in we add this line in the home.php file
// to redirect the user to the login page
<?php
    }else{
        header("location:http://localhost/todoPhp/index.php?msg=login_first");
    }
?>

todo.php

To add the functionality for adding and deleting the todo’s we define all the backend logic in assets/backend/tood.php.

<?php
    include 'db_connection.php';
    $user_id = $_SESSION['user_id'];
    // =========== Fetch tasks list ==========
    $select = "SELECT * FROM `todolist` WHERE user_id = '$user_id'";
    $s_query = mysqli_query($conn,$select);
    // $row = mysqli_fetch_assoc($query);
    // =========== ADD TASKS =========
    $tasks = $_POST['add-todo'];
    if(isset($_POST['add-todo-btn'])){
        $insert = "INSERT INTO `todolist`(`user_id`, `tasks`, `created_at`, `updated_at`) VALUES ('$user_id','$tasks', CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)";
        $query = mysqli_query($conn,$insert);
        if($query){
            echo "<script> window.location='../../home.php';</script>";
        }else{
            // echo $user_id;
            echo "<script>alert('Something Went wrong...try again!!'); window.location='../../home.php';</script>";
        }
    }
    // ============== Delete Task ===========
    if(isset($_POST['dlt-todo-btn'])){
        $row_id = $_GET['id'];
        $delete = "DELETE FROM `todolist` WHERE id = $row_id";
        $d_query = mysqli_query($conn,$delete);
        if($d_query){
            echo "<script> window.location='../../home.php';</script>";
        }else{
            // echo $row['id'];
            echo "<script>alert('Something Went wrong...try again!!'); window.location='../../home.php';</script>";
        }
    }
?>

style.css

On top of the usual to make the project more pleasing we add the styles.css file in our assets/css folder.

.login-form{
    margin : 5% auto;
}
 
.logout-btn a{
    text-decoration : none;
    color : #000000;
}
 
#add-todo-form{
    display : none;
 
}
 
.hidden{
    display : none;
}

To bundle up the whole project of the ToDo App in PHP, this is the zip file for it, after downloading the zip file extract it and place it in the htdocs folder of your c/xampp folder. After this create a new table by visiting the localhost/PHPMyAdmin and import the SQL file from the zip file. After this, you can run the project by visiting localhost/todoPhp/index.php.

Thank you for visiting our website.


Also Read:

Share:

Author: Ayush Purawr