How to Make Facebook style Friend Request System in PHP?

Here you will learn how to make a friend request system like Facebook using PHP with MySQL database.

Features of this friend request system:

  • Login and Sign up.
  • A user can send, accept, ignore, and cancel a friend request.
  • Request Notification.
  • Unfriend a friend.
  • Total number of friends.

Let’s make a friend request system step by step:

PHP Friend request system folder structure

1. Database Setup:

Here is the database info and table structure –

  • Database Name: frnd_req_system
  • Tables:
    • usersid, name, email, password
    • friend_requestssender, receiver
    • friendsuser_one, user_two

As reference key: sender, receiver, user_one, user_two – all referencing the Foreign key from the users(id) table.

Use the following SQL code to build the frnd_req_system database structure –

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 */;


CREATE TABLE `friends` (
  `user_one` int(11) NOT NULL,
  `user_two` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `friend_requests` (
  `sender` int(11) NOT NULL,
  `receiver` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `name` varchar(30) NOT NULL,
  `email` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;


ALTER TABLE `friends`
  ADD KEY `user_one` (`user_one`),
  ADD KEY `user_two` (`user_two`);

ALTER TABLE `friend_requests`
  ADD KEY `sender` (`sender`),
  ADD KEY `receiver` (`receiver`);

ALTER TABLE `users`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `email` (`email`);


ALTER TABLE `users`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;


ALTER TABLE `friends`
  ADD CONSTRAINT `friends_ibfk_1` FOREIGN KEY (`user_one`) REFERENCES `users` (`id`) ON DELETE CASCADE,
  ADD CONSTRAINT `friends_ibfk_2` FOREIGN KEY (`user_two`) REFERENCES `users` (`id`) ON DELETE CASCADE;

ALTER TABLE `friend_requests`
  ADD CONSTRAINT `friend_requests_ibfk_1` FOREIGN KEY (`sender`) REFERENCES `users` (`id`) ON DELETE CASCADE,
  ADD CONSTRAINT `friend_requests_ibfk_2` FOREIGN KEY (`receiver`) REFERENCES `users` (`id`) ON DELETE CASCADE;
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 */;

Alternative database structure:

You can also do the following where you will have only one table to handle the requests

  • users table:
    • id (Primary key)
    • name
    • Other user-related fields
  • friend_requests table:
    • id (Primary key)
    • sender_id (Foreign key referencing users table)
    • receiver_id (Foreign key referencing users table)
    • status (Pending/Accepted/Rejected)

2. Graphical explanation:

Graphical explanation of the PHP friend request system

3. Building the Classes:

All the classes will be inside the classes folder –

  • Database.php – Contains the code for database connection.
  • User.phpLogin, Register, and Fetch users with validation.
  • Friend.phpHandles the friend request actions such as – send, accept, ignore, unfriend, etc.
<?php
class Database
{
    private $db_host = 'localhost';
    private $db_name = 'frnd_req_system';
    private $db_username = 'root';
    private $db_password = '';
    function __construct()
    {
        try {
            $dsn = "mysql:host={$this->db_host};dbname={$this->db_name};charset=utf8";
            $db_connection = new PDO($dsn, $this->db_username, $this->db_password);
            $db_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $db_connection;
        } catch (PDOException $e) {
            echo "Connection error " . $e->getMessage();
            exit;
        }
    }
}
<?php
require_once __DIR__ . "/Database.php";
class User extends Database
{
    protected $conn;
    function __construct()
    {
        $this->conn = parent::__construct();
    }

    protected function is_valid_email($email)
    {
        return (!preg_match(
            "^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$^",
            $email
        )) ? FALSE : TRUE;
    }

    protected function field_validation(array $fields)
    {
        $empty_fields = [];
        foreach ($fields as $key => $val) {
            if (empty($val)) {
                $empty_fields[$key] = "Must not be empty.";
            } elseif ($key === "email" && !$this->is_valid_email($val)) {
                $empty_fields[$key] = "Invalid email address";
            }
        }

        if (count($empty_fields) && (count($empty_fields) <= count($fields))) {
            return [
                "ok" => 0,
                "field_error" => $empty_fields
            ];
        }
        return false;
    }

    function register($name, $email, $password)
    {
        $data = [];
        $data["name"] = trim(htmlspecialchars($name));
        $data["email"] = trim($email);
        $data["password"] = trim($password);

        $errors = $this->field_validation($data);
        if ($errors) return $errors;

        try {
            $email = $data["email"];

            $query = $this->conn->query("SELECT * FROM `users` WHERE `email`= '$email'");

            if ($query->rowCount() !== 0) {
                return [
                    "ok" => 0,
                    "field_error" => ["email" => "This Email is already registered."]
                ];
            }

            $password = password_hash($data["password"], PASSWORD_DEFAULT);
            $sql = "INSERT INTO `users` (`name`, `email`, `password`) VALUES(?,?,?)";
            $stmt = $this->conn->prepare($sql);
            $stmt->bindParam(1, $data["name"], PDO::PARAM_STR);
            $stmt->bindParam(2, $data["email"], PDO::PARAM_STR);
            $stmt->bindParam(3, $password, PDO::PARAM_STR);
            $stmt->execute();
            return [
                "ok" => 1,
                "message" => "You have been registered successfully."
            ];
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit;
        }
    }

    function login($email, $password)
    {
        $data = [];
        $data["email"] = trim($email);
        $data["password"] = trim($password);

        $errors = $this->field_validation($data);
        if ($errors) return $errors;

        try {
            $query = $this->conn->query("SELECT * FROM `users` WHERE `email`= '{$data["email"]}'");

            if ($query->rowCount() === 0) {
                return [
                    "ok" => 0,
                    "field_error" => ["email" => "This email is not registered."]
                ];
            }
            $user = $query->fetch(PDO::FETCH_ASSOC);
            $password_match = password_verify($data["password"], $user['password']);
            if (!$password_match) {
                return [
                    "ok" => 0,
                    "field_error" => ["password" => "Incorrect Password."]
                ];
            }
            $_SESSION['user_id'] = $user["id"];
            header("Location: home.php");
            exit;
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit;
        }
    }

    function find_by_id($id)
    {
        if (!filter_var($id, FILTER_VALIDATE_INT)) {
            return false;
        }
        try {
            $query = $this->conn->query("SELECT `id`, `name`, `email` FROM `users` WHERE `id`= '$id'");
            if ($query->rowCount() === 0) return null;
            return $query->fetch(PDO::FETCH_OBJ);
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit;
        }
    }

    function find_all_except($id)
    {
        if (!filter_var($id, FILTER_VALIDATE_INT)) {
            return false;
        }

        try {
            $query = $this->conn->query("SELECT `id`, `name`, `email` FROM `users` WHERE `id` != '$id' ORDER BY `id` DESC");
            if ($query->rowCount() === 0) return null;
            return $query->fetchAll(PDO::FETCH_OBJ);
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit;
        }
    }
}
<?php
require_once __DIR__ . "/Database.php";
class Friend extends Database
{
    protected $conn;
    protected $my_id;
    protected $user_id;
    function __construct()
    {
        $this->conn = parent::__construct();
    }

    protected function id_validation(array $ids)
    {

        foreach ($ids as $val) {
            if (!filter_var($val, FILTER_VALIDATE_INT)) {
                return false;
            }
        }
        return true;
    }

    protected function run_query($condition, $full_query = false, $table_name = "friend_requests")
    {
        if (!$this->id_validation([$this->my_id, $this->user_id])) return false;

        try {
            $sql = "SELECT * FROM `$table_name` WHERE $condition";
            if ($full_query) $sql = $full_query;
            $query = $this->conn->query($sql);
            if ($query->rowCount() === 0) return null;
            return true;
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit;
        }
    }

    // Redirect to the user profile
    protected function profile_redirect()
    {
        header('Location: profile.php?id=' . $this->user_id);
        exit;
    }

    function is_already_friends($my_id, $user_id)
    {
        $this->my_id = $my_id;
        $this->user_id = $user_id;
        $result = $this->run_query("(`user_one` = '$my_id' AND `user_two` = '$user_id') OR (`user_one` = '$user_id' AND `user_two` = '$my_id')", false, "friends");
        return $result;
    }

    // Am i the request sender or receiver
    function am_i_the_req($_, $my_id, $user_id)
    {
        $this->my_id = $my_id;
        $this->user_id = $user_id;
        if ($_ === "sender") {
            return $this->run_query("`sender` = '$my_id' AND `receiver` = '$user_id'");
        } elseif ($_ === "receiver") {
            return $this->run_query("`sender` = '$user_id' AND `receiver` = '$my_id'");
        }
        echo "Parameter must be 'sender' or 'receiver'";
        exit;
    }

    function is_request_already_sent($my_id, $user_id)
    {
        try {
            $this->my_id = $my_id;
            $this->user_id = $user_id;
            return $this->run_query("(sender = '$my_id' AND receiver = '$user_id') OR (sender = '$user_id' AND receiver = '$my_id')");
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }

    function pending_friends($my_id, $user_id)
    {
        try {
            $this->my_id = $my_id;
            $this->user_id = $user_id;
            $sql = "INSERT INTO `friend_requests`(`sender`, `receiver`) VALUES('$my_id','$user_id')";
            $this->run_query(NULL, $sql);
            $this->profile_redirect();
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }

    function cancel_or_ignore_friend_request($my_id, $user_id, $action)
    {
        $this->my_id = $my_id;
        $this->user_id = $user_id;

        if ($action == "cancel") {
            $sql = "DELETE FROM `friend_requests` WHERE `sender` = '$my_id' AND `receiver` = '$user_id'";
        } elseif ($action == "ignore") {
            $sql = "DELETE FROM `friend_requests` WHERE `sender` = '$user_id' AND `receiver` = '$my_id'";
        } else {
            $sql = "DELETE FROM `friend_requests` WHERE (`sender` = '$my_id' AND `receiver` = '$user_id') OR (`sender` = '$user_id' AND `receiver` = '$my_id')";
        }
        try {
            $this->run_query(NULL, $sql);
            $this->profile_redirect();
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }

    function make_friends($my_id, $user_id)
    {
        $this->my_id = $my_id;
        $this->user_id = $user_id;

        try {
            $sql = "DELETE FROM `friend_requests` WHERE (`sender` = '$my_id' AND `receiver` = '$user_id') OR (`sender` = '$user_id' AND `receiver` = '$my_id')";
            $result = $this->run_query(NULL, $sql);
            if ($result) {
                $sql = "INSERT INTO `friends`(`user_one`, `user_two`) VALUES('$my_id', '$user_id')";
                $this->run_query(NULL, $sql);
            }
            $this->profile_redirect();
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }

    function delete_friends($my_id, $user_id)
    {
        $this->my_id = $my_id;
        $this->user_id = $user_id;

        try {
            $sql = "DELETE FROM `friends` WHERE (`user_one` = '$my_id' AND `user_two` = '$user_id') OR (`user_one` = '$user_id' AND `user_two` = '$my_id')";
            $this->run_query(NULL, $sql);
            $this->profile_redirect();
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }

    function request_notification($my_id, $return_data = false)
    {
        if (!$this->id_validation([$my_id])) return false;
        try {

            $sql = "SELECT `sender`, `name`, users.id as `u_id` FROM `friend_requests` JOIN `users` ON friend_requests.sender = users.id WHERE `receiver` = '$my_id'";

            $result = $this->conn->query($sql);

            if ($return_data) {
                return $result->fetchAll(PDO::FETCH_OBJ);
            }
            return $result->rowCount();
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }

    function get_all_friends($my_id, $return_data = false)
    {

        if (!$this->id_validation([$my_id])) return false;

        try {
            $sql = "SELECT * FROM `friends` WHERE `user_one` = '$my_id' OR user_two = '$my_id'";
            $result = $this->conn->query($sql);
            if ($return_data) {
                $ids = [];
                $data = $result->fetchAll(PDO::FETCH_OBJ);
                if (count($data) === 0) return [];
                foreach ($data as $row) {
                    if ($row->user_one == $my_id) {
                        $ids[] = $row->user_two;
                        continue;
                    }
                    $ids[] = $row->user_one;
                }

                $sql = "SELECT `id`, `name` FROM `users` WHERE `id` IN (" . implode(',', array_map('intval', $ids)) . ")";
                return $this->conn->query($sql)->fetchAll(PDO::FETCH_OBJ);
            }
            return $result->rowCount();
        } catch (PDOException $e) {
            $e->getMessage();
            exit;
        }
    }
}

3. Creating the files of the root folder

init.php: contains session() and autoloading classes

<?php
session_start();
session_regenerate_id(true);

// Autoloading Classes
spl_autoload_register(function ($class_name) {
    $path = __DIR__ . "/classes/";
    $theClass = "{$path}{$class_name}.php";
    if (file_exists($theClass)) return require_once $theClass;
    exit("Error: The \"{$class_name}\" class not found in {$path} || Or check your spelling.");
});

Register, Login, & Logout

Registration from for a new user
<?php
require_once __DIR__ . "/init.php";
$result = NULL;
if (isset($_SESSION['user_id'])) {
    header('Location: home.php');
    exit;
} else if (isset($_POST['email']) && isset($_POST['name']) && isset($_POST['password'])) {
    $User = new User();
    $result = $User->register($_POST['name'], $_POST['email'], $_POST['password']);
}
function old_val($field_name)
{
    global $result;
    if (isset($result["ok"]) && $result["ok"]) return "";
    if (isset($_POST[$field_name])) return htmlspecialchars($_POST[$field_name]);
    return "";
} ?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Register</title>
    <link rel="stylesheet" href="./assets/style.css">
</head>

<body>
    <div class="container form">
        <h1>Register</h1>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="POST" novalidate>
            <label for="name">Name: <span class="err-msg name"></span></label>
            <input class="form-input" type="text" name="name" id="name" placeholder="Your name" value="<?php echo old_val("name"); ?>">

            <label for="email">Email: <span class="err-msg email"></span></label>
            <input class="form-input" type="email" name="email" id="email" placeholder="Your email" value="<?php echo old_val("email"); ?>">

            <label for="pass">Password: <span class="err-msg password"></span></label>
            <input class="form-input" type="password" name="password" id="pass" placeholder="Password" value="<?php echo old_val("password"); ?>">
            <?php if (isset($result['ok']) && isset($result['message']) && $result['ok'] === 1) : ?>
                <p class="s-msg">✔️ <?php echo $result['message']; ?> You may <a href="./login.php">login</a> now.</p>
            <?php endif; ?>

            <input class="button" type="submit" value="Login">
        </form>
        <p class="link"><a href="./login.php">Login</a></p>
    </div>
    <?php if (isset($result["field_error"])) : ?>
        <script>
            let spanItem;
            let item;
            const errs = <?php echo json_encode($result["field_error"]); ?>;
            for (const property in errs) {
                spanItem = document.querySelector(`.err-msg.${property}`);
                item = document.querySelector(`[name="${property}"]`);
                item.classList.add('with-error');
                spanItem.innerText = errs[property];
            }
        </script>
    <?php endif; ?>
</body>

</html>
login form
<?php
require_once __DIR__ . "/init.php";
$result = NULL;
if (isset($_SESSION['user_id'])) {
    header('Location: home.php');
    exit;
} else if (isset($_POST['email']) && isset($_POST['password'])) {
    $User = new User();
    $result = $User->login($_POST['email'], $_POST['password']);
}
function old_val($field_name)
{
    if (isset($_POST[$field_name])) return htmlspecialchars($_POST[$field_name]);
    return "";
}
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
    <link rel="stylesheet" href="./assets/style.css">
</head>

<body>
    <div class="container form">
        <h1>Login</h1>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="POST" novalidate>
            <label for="email">Email: <span class="err-msg email"></span></label>
            <input class="form-input" type="email" name="email" id="email" placeholder="Your email" value="<?php echo old_val("email"); ?>">
            <label for="pass">Password: <span class="err-msg password"></span></label>
            <input class="form-input" type="password" name="password" id="pass" placeholder="Password" value="<?php echo old_val("password"); ?>">
            <input class="button" type="submit" value="Login">
        </form>
        <p class="link"><a href="./register.php">Register</a></p>
    </div>

    <?php if (isset($result["field_error"])) : ?>
        <script>
            let spanItem;
            let item;
            const errs = <?php echo json_encode($result["field_error"]); ?>;
            for (const property in errs) {
                spanItem = document.querySelector(`.err-msg.${property}`);
                item = document.querySelector(`[name="${property}"]`);
                item.classList.add('with-error');
                spanItem.innerText = errs[property];
            }
        </script>
    <?php endif; ?>

</body>

</html>
<?php
// Initialize the session.
// If you are using session_name("something"), don't forget it now!
session_start();

// Unset all of the session variables.
$_SESSION = array();

// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(
        session_name(),
        '',
        time() - 42000,
        $params["path"],
        $params["domain"],
        $params["secure"],
        $params["httponly"]
    );
}

// Finally, destroy the session.
session_destroy();
header("Location: login.php");
exit;

actions.php: Performs all friend request actions

<?php
require_once __DIR__ . "/init.php";
$actions = ["send", "unfriend", "cancel", "ignore", "accept"];
function redirect_to_home(){
    header('Location: home.php');
    exit;
}

if (
    !isset($_SESSION['user_id']) ||
    !isset($_GET["id"]) ||
    !isset($_GET["action"]) ||
    !in_array($_GET["action"], $actions) ||
    !filter_var($_GET["id"], FILTER_VALIDATE_INT) ||
    $_GET["id"] == $_SESSION['user_id']
) redirect_to_home();

$action = $_GET["action"];

$User = new User();

$the_user = $User->find_by_id($_SESSION['user_id']);
$x_user = $User->find_by_id($_GET['id']);

if (!$the_user || !$x_user) redirect_to_home();

$my_id = $the_user->id;
$user_id = $x_user->id;

$Friend = new Friend();

if (
    $action === $actions[0] &&
    !($Friend->is_already_friends($my_id, $user_id) || $Friend->is_request_already_sent($my_id, $user_id))
) {
    $Friend->pending_friends($my_id, $user_id);
}
elseif (
    in_array($action, [$actions[2], $actions[3]]) &&
    $Friend->is_request_already_sent($my_id, $user_id)
) {
    $Friend->cancel_or_ignore_friend_request($my_id, $user_id, $action);
}
elseif (
    $action === $actions[4] &&
    !$Friend->is_already_friends($my_id, $user_id) &&
    $Friend->is_request_already_sent($my_id, $user_id)
) {
    $Friend->make_friends($my_id, $user_id);
}
elseif (
    $action === $actions[1] &&
    $Friend->is_already_friends($my_id, $user_id)
) {
    $Friend->delete_friends($my_id, $user_id);
}
else {
    redirect_to_home();
}

After a user has logged in:

  • nav.php – A component that contains dynamic navigation links.
  • home.php – home page of the logged-in user.
  • friends.php – Friends list of the logged-in user.
  • profile.php – logged-in user can see other users’ profiles and send them friend requests.
  • notification.php – Notifications for friend-request.
<?php
function the_nav(int $notification = 0, int $total_friends = 0, $page = null)
{
    $n_badge = $notification ? '<span class="badge active">' . $notification . '</span>' : '<span class="badge">' . $notification . '</span>';
    $f_badge = '<span class="badge">' . $total_friends . '</span>';
?>
    <ul class="p_list d-flex">
        <li><?php echo ($page == "home") ? '<span>Home</span>' : '<a href="./home.php" class="active">Home</a>'; ?></li>

        <li><?php echo ($page == "info") ? "<span>Notification $n_badge</span>" : '<a href="./notifications.php">Notification ' . $n_badge . '</a>'; ?></li>

        <li><?php echo ($page == "frnd") ? "<span>Friends $f_badge</span>" : '<a href="./friends.php" class="active">Friends ' . $f_badge . '</a>'; ?></li>
        <li><a href="./logout.php">Logout</a></li>
    </ul>
<?php } ?>
home page
<?php
require_once __DIR__ . "/init.php";
if (!isset($_SESSION['user_id'])) {
    header('Location: logout.php');
    exit;
}
$User = new User();
$the_user = $User->find_by_id($_SESSION['user_id']);
if (!$the_user) {
    header('Location: logout.php');
    exit;
}
require_once __DIR__ . "/nav.php";
$all_users = $User->find_all_except($the_user->id);

$Friend = new Friend();
$notification = $Friend->request_notification($the_user->id);
$total_friends = $Friend->get_all_friends($the_user->id);
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home</title>
    <link rel="stylesheet" href="./assets/style.css">
</head>

<body>

    <div class="container profile">
        <div class="profile">
            <div class="p_user d-flex">
                <img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $the_user->id; ?>" alt="<?php echo $the_user->name; ?>">
                <h2><?php echo $the_user->name; ?></h2>
                <?php the_nav($notification, $total_friends); ?>
            </div>
        </div>
        <?php if ($all_users && count($all_users)) : ?>
            <h2 class="p-title">👥 All Users</h2>
            <div class="all-users">
                <ul class="user-list d-flex">
                    <?php foreach ($all_users as $user) : ?>
                        <li><a href="./profile.php?id=<?php echo $user->id; ?>"><img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $user->id; ?>" alt=""><span><?php echo $user->name; ?></span></a></li>
                    <?php endforeach; ?>
                </ul>
            </div>
        <?php endif; ?>
    </div>
</body>

</html>
friends page
<?php
require_once __DIR__ . "/init.php";
if (!isset($_SESSION['user_id'])) {
    header('Location: logout.php');
    exit;
}
$User = new User();
$the_user = $User->find_by_id($_SESSION['user_id']);
if (!$the_user) {
    header('Location: logout.php');
    exit;
}
require_once __DIR__ . "/nav.php";
$all_users = $User->find_all_except($the_user->id);

$Friend = new Friend();
$notification = $Friend->request_notification($the_user->id);
$all_firends = $Friend->get_all_friends($the_user->id, true);
$total_friends = count($all_firends);
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Friend List</title>
    <link rel="stylesheet" href="./assets/style.css">
</head>

<body>

    <div class="container profile">
        <div class="profile">
            <div class="p_user d-flex">
                <img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $the_user->id; ?>" alt="<?php echo $the_user->name; ?>">
                <h2><?php echo $the_user->name; ?></h2>
                <?php the_nav($notification, $total_friends, "frnd"); ?>
            </div>
        </div>
        <?php if ($all_firends && count($all_firends)) : ?>
            <h2 class="p-title">🧑‍🤝‍🧑 Your Friends </h2>
            <div class="all-users">
                <ul class="user-list d-flex">
                    <?php foreach ($all_firends as $user) : ?>
                        <li><a href="./profile.php?id=<?php echo $user->id; ?>"><img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $user->id; ?>" alt=""><span><?php echo $user->name; ?></span></a></li>
                    <?php endforeach; ?>
                </ul>
            </div>
        <?php else :
            echo '<h2 class="p-title">You have no friends.</h2>';
        endif; ?>
    </div>
</body>

</html>
user profile page send friend request
<?php
require_once __DIR__ . "/init.php";
if (!isset($_SESSION['user_id'])) {
    header('Location: logout.php');
    exit;
}
$User = new User();
$the_user = $User->find_by_id($_SESSION['user_id']);
if (!$the_user) {
    header('Location: logout.php');
    exit;
}
if (!isset($_GET['id']) || $_GET['id'] === $the_user->id) {
    header('Location: home.php');
    exit;
}
$x_user = $User->find_by_id($_GET['id']);
if (!$x_user) {
    header('Location: home.php');
    exit;
}
require_once __DIR__ . "/nav.php";

$Friend = new Friend();

$notification = $Friend->request_notification($the_user->id);
$total_friends = $Friend->get_all_friends($the_user->id);

$req_receiver = $Friend->am_i_the_req("receiver", $the_user->id, $x_user->id);
$req_sender = $Friend->am_i_the_req("sender", $the_user->id, $x_user->id);
$already_friends = $Friend->is_already_friends($the_user->id, $x_user->id);
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home</title>
    <link rel="stylesheet" href="./assets/style.css">
</head>

<body>

    <div class="container profile">
        <div class="profile">
            <div class="p_user d-flex">
                <img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $x_user->id; ?>" alt="<?php echo $the_user->name; ?>">
                <h2><?php echo $x_user->name; ?></h2>
                <?php the_nav($notification, $total_friends); ?>
            </div>
        </div>
        <div class="actions">
            <?php
            $id = $x_user->id;
            if ($already_friends) {
                echo '<a href="./actions.php?id=' . $id . '&action=unfriend" class="btn btn-2">Unfriend</a>';
            } elseif ($req_sender) {
                echo '<a href="./actions.php?id=' . $id . '&action=cancel" class="btn btn-2">Cancel Request</a>';
            } elseif ($req_receiver) {
                echo '<a href="./actions.php?id=' . $id . '&action=ignore" class="btn btn-2">Ignore</a> &nbsp;<a href="./actions.php?id=' . $id . '&action=accept" class="btn btn-1">Accept</a>';
            } else {
                echo '<a href="./actions.php?id=' . $id . '&action=send" class="btn btn-1">Send Request</a>';
            }
            ?>
        </div>
    </div>
</body>

</html>
friend request notification page
<?php
require_once __DIR__ . "/init.php";
if (!isset($_SESSION['user_id'])) {
    header('Location: logout.php');
    exit;
}
$User = new User();
$the_user = $User->find_by_id($_SESSION['user_id']);
if (!$the_user) {
    header('Location: logout.php');
    exit;
}
require_once __DIR__ . "/nav.php";
$all_users = $User->find_all_except($the_user->id);

$Friend = new Friend();
$req_senders = $Friend->request_notification($the_user->id, true);
$total_friends = $Friend->get_all_friends($the_user->id);
$req_num = $req_senders ? count($req_senders) : 0;
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo $req_num . ' Friend', (in_array($req_num, [0, 1])) ? ' Request' : ' Requests'; ?></title>
    <link rel="stylesheet" href="./assets/style.css">
</head>

<body>

    <div class="container profile">
        <div class="profile">
            <div class="p_user d-flex">
                <img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $the_user->id; ?>" alt="<?php echo $the_user->name; ?>">
                <h2><?php echo $the_user->name; ?></h2>
                <?php the_nav($req_num, $total_friends, "info"); ?>
            </div>
        </div>
        <?php if ($all_users && count($all_users)) : ?>
            <h2 class="p-title">You have <?php echo $req_num . ' Friend ', (in_array($req_num, [0, 1])) ? 'Request' : 'Requests'; ?></h2>
            <div class="all-users">
                <ul class="user-list d-flex">
                    <?php foreach ($req_senders as $user) : ?>
                        <li><a href="./profile.php?id=<?php echo $user->u_id; ?>"><img src="https://api.dicebear.com/6.x/bottts/png?seed=<?php echo $user->u_id; ?>" alt=""><span><?php echo $user->name; ?></span></a></li>
                    <?php endforeach; ?>
                </ul>
            </div>
        <?php endif; ?>
    </div>
</body>

</html>

Download the full source code from – GitHub.

Thank You.. 🙏🏻❤️❤️