It seems like you are using an ad blocker. To enhance your experience and support our website, please consider:

  1. Signing in to disable ads on our site. Our users don't see ads
  2. Or, Sign up if you don't have an account yet
  3. Or, disable your adblocker by doing this:
    • Click on the adblocker icon in your browser's toolbar.
    • Select "Pause on this site" or a similar option for lancecourse.com.

Make your first CRUD with PHP - Part 2 : Admin login panel

By zooboole

Here we are in the second part of this tutorial. As I said in part 1 today we'll be building the admins login panel.

Before that let me explain a bit how we're going to do that. we'll Create a page which contains a form asking a username and a password to the admin, once he inputs this data we will query our database to check in the admins table if this particular admin's information is in it.

If the data is in, *in the same order then, we create a session for him and redirect him to the admins dashboard.

Once in the dashboard we can give him a simple menu which can allow him to add other admins, edit his username and password, or logout.

In case his information doesn't correspond to any data record, we will redirect him back to the login page with an error message.

The following sketch shows a bit how it's going to be.

Dataflow Admin log in

Prerequisities

Following are things you need to know or muster in order to understand this tutorial very well:

  • Include
  • Sessions
  • Object Oriented Programming
  • MySQL

Data model

Create a new database and name it pms or something else more convenient to your case. Create a new table and name it admins as following:

--
-- Table structure for table `admins`
--

CREATE TABLE IF NOT EXISTS `admins` (
  `idadmins` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(122) NOT NULL,
  `password` varchar(80) NOT NULL,
  PRIMARY KEY (`idadmins`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- Dumping data for table `admins`
--
INSERT INTO `admins` (`idadmins`, `username`, `password`) VALUES
(1, 'admin', '$2y$10$7FtETUEgG6Ek7cCIhyWFi.gORwHHsBZd8iOyx01W7DCxrznWi7DCG');

Coding the logging in system

We're going to code base on the folder structure defined in part1. I have created new files and folders in order to accomplish our task. Therefore, we have following:

Folder Structure

index.php

<?php

    // Start from getting the header which contains some settings we need
    require_once 'includes/header.php';

    // Prevent admin from comming back here
    // if he's already logged in
    if (isset($_SESSION['admin_session']) )
    {
        $commons->redirectTo(SITE_PATH.'dashboard.php');
    }

?>

<html>
    <head>
        <title>Products Management System | Admin Panel</title>
        <link href='https://fonts.googleapis.com/css?family=Oswald:400,300' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
        <link rel="stylesheet" href="public/css/CreativeButtons/css/component.css">
        <link rel="stylesheet" href="public/css/style.css">
    </head>

    <body>
        <main class="container">

            <div class="admin-box">
                <h3><i class="fa fa-lock"></i> Admin Access</h3>

                <?php  if ( isset($_SESSION['error']) ): ?>
                    <div class="pannel panel-warning">
                        <?= $_SESSION['error'] ?>
                    </div>
                <?php session::destroy('error'); endif ?>

                <form action="admin-access.php" method="post">
                    <div>
                        <label for="username">Username</label>
                        <input type="text" name="username" id="username" placeholder="zooboole">
                    </div>
                    <div>
                        <label for="password">Password</label>
                        <input type="password" name="password" id="password" placeholder="MySecr3t Pass WORD">
                    </div>
                    <div class="activate">
                        <button type="submit" class="btn btn-1 btn-1a">Log in</button>
                    </div>
                </form>
            </div>

            <footer>
                <?= date("Y") ?> &copy;  lancecourse.com - Project by <a href="http://zooboole.me" target="_blank">zooboole</a> - Credit to <a href="http://tympanus.net/codrops/2013/06/13/creative-button-styles/" target="_blank">tympanus.net</a>
            </footer>
        </main>
    </body>
</html>

This file is the starting point of the application. It provide a form asking a user to log in with his username and password.

At its very beginning there is a block of PHP code:

<?php

    // Start from getting the header which contains some settings we need
    require_once 'includes/header.php';

    // Prevent admin from comming back here
    // if he's already logged in
    if (isset($_SESSION['admin_session']) )
    {
        $commons->redirectTo(SITE_PATH.'dashboard.php');
    }

?>

This code includes the includes/header.php file, then checks if a user is already connected, he shouldn't stay there, he should rather be redirected to the admins dashboard.

In the other hand you can notice the variable $commons and the function redirectTo() which are not PHP core elements. Indeed, these two elements have been declared in the includes/header.php file. So, let's go in that file and see what we have.

includes/header.php

<?php

// Get the application settings and parameters

require_once "config/params.php";
require_once ROOT."../includes/classes/session.php";
require_once ROOT."dbconnection.php";
require_once ROOT."../includes/classes/commons.php";

// Start the session if it's not yet started 
// and make it available on 
// all pages which include the header.php
!isset($_SESSION) ? session::init(): null;

// Get some common objects ready for various files
$dbh    = new Dbconnect();
$commons = new Commons($dbh);

The code in this file is very important to all the application, because it provides all needed settings in all files which include it.

First, it includes the parameters file, config/params.php because this file contains basic variables like ROOT, SITE_PATH, needed to access the application's files. Look at its content below:

config/params.php

<?php 

    // Show all types of errors
    // To change into 0 in production or comment the two lines out
    ini_set('display_errors',1);
    error_reporting(E_ALL);

    define("DS", DIRECTORY_SEPARATOR);
    define('ROOT', __DIR__.'/');
    define("SITE_PATH","http://localhost/pms/");

This file contains the declaration of some useful constants:

  • DS for DIRECTORY_SEPARATOR which is either / or backslash depending on the OS.
  • ROOT to helps us access the root folder of the project. This helps to include files.
  • SITE_PATH is the URL of the project.

note that you can decide to name these constants with different names of your choice.

includes/classes/session.php

<?php

class session
{

    /*
     * Start the session
     *
     */
    public static function init ()
    {
        @session_start();
    }

    /*
     * Set session key
     *
     */
    public static function set ($key, $value)
    {
        $_SESSION[$key] = $value;
        return true;
    }

    /*
     * Get a session from the key
     *
     */
    public static function get ($key)
    {
       return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
    }

    /*
     * Unsets a session through the key
     *
     */
    public static function destroy ($key)
    {
        unset($_SESSION[$key]);
        //session_destroy();
    }

    /*
     * Function to be in charge of encrypting our password
     * Make sure you make is as more secured as possible you can
     * if you want to use it in serious projects
     *
     */
    public static function hashPassword($password)
    {
        return password_hash($password, PASSWORD_DEFAULT);
    }

    /*
     * Function our encrypted password
     * You can change the function structure based on the hashing function
     *
     */
    public static function passwordMatch($password, $hash)
    {
        return password_verify($password, $hash);
    }

}

This class contains some helpers. There are static functions which can be access at any point of our application. It mostly provides functions for the manupulation of sessions.

config/dbconnection.php

<?php

        /**
        * DB Connection class
        */
        class Dbconnect extends PDO
        {
            // Change the database setting with yours accordingly
            private $dbengine   = 'mysql';
            private $dbhost     = 'localhost';
            private $dbuser     = 'DbUserName';
            private $dbpassword = 'YourDbPassword';
            private $dbname     = 'pms';

            // Set the database handler to null
            public $dbh = null;

            function __construct()
            {
                try{

                    // Connect to the database and save the DB instance in $dbh
                    $this->dbh = new PDO("".$this->dbengine.":host=$this->dbhost; dbname=$this->dbname", $this->dbuser, $this->dbpassword);

                    // This will allow me to have objects format of my data everytime i fetch from my database
                    // Or we'll have to do it in each function in which we query data from database
                    $this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

                }
                catch (PDOException $e){
                    // if any error throw an exception
                    $e->getMessage();
                }
            }

        }

This class is in charge of connecting our applcation to the database and returns a PDO object which can be used anywhere to query our database.

includes/classes/commons.php

<?php

    /**
     * Class of common functions
     */
    class Commons
    {

        private $dbh = null;
        public function __construct($db)
        {
            $this->dbh = $db;
        }

        /**
         * Check username
         */
        public function isAvailableUsername($username)
        {
            $request = $this->dbh->prepare("SELECT username FROM admins WHERE username = ?");
            return $request->execute( array($username) );
        }

        /*
         * Check if a field is empty or not
         */
        public function isFieldEmpty($field)
        {
            if ( isset($field) && ( empty($field) || trim($field)  == '' ) )
            {
                return true;
            }else{
                return false;
            }
        }

        /*
         * Redirecting helper
         */
        public function redirectTo($url)
        {
            if (!headers_sent())
            {
                header('location:'.$url);
                exit;
            }else{
                print '<script type="text/javascript">';
                print 'window.location.href="'.$url.'";';
                print '</script>';

                print '<noscript>';
                print '<meta http-equiv="refresh" content="0;url='.$url.'" />';
                print '</noscript>'; exit;
            }
        }

    }

I have planned to add this class for us to put in all commonn tasks we have between our admins, products and much more which are not specific to any of them.

We can see that the header.php file is the service provider to our application. Whereever we need those services we have to include the file. And you can notice that in index.php, dashboard.php and in admin-access.php.

Again in the index.php file, just after including the header, we have the form requesting for the username and password of the admin. The action of this form points to another file: admin-access.php. That file is in charge of validating and conection the admin.

admin-access.php

<?php

    /*
     * We process the admin login form here
     */

    // Start from getting the hader which contains some settings we need
    require_once 'includes/header.php';

    // require the admins class which containes most functions applied to admins
    require_once ROOT."../includes/classes/admin-class.php";

    $admins     = new Admins($dbh);

    // Let's process the form now
    // Starting by checking if the forme has been submitted
    if (!isset($_POST) || sizeof($_POST) == 0 )
    {
        session::set('error', 'Submit the form first.');
        $commons->redirectTo(SITE_PATH.'index.php');
    }

    // If the form is submitted, let's check if the fields are not empty
    if ($commons->isFieldEmpty($_POST['username']) || $commons->isFieldEmpty($_POST['password']) ) 
    {
        session::set('error', 'All fields are required.');
        $commons->redirectTo(SITE_PATH.'index.php');

    }

    // Now let's check if the the username and password match a line in our table

    $username = htmlspecialchars( $_POST['username'], ENT_QUOTES, 'UTF-8' );
    $password = htmlspecialchars( $_POST['password'], ENT_QUOTES, 'UTF-8' );

    if (!$admins->loginAdmin($username, $password)) 
    {
        session::set('error', 'Cannot connect you. Check your credentials.');
        $commons->redirectTo(SITE_PATH.'index.php');

    }

    // Otherwise we can set a session to the admin and send him to the dashboard
    // The session will hold only the username.
    session::set('admin_session', $username);
    $commons->redirectTo(SITE_PATH.'dashboard.php');

This file is located at the root folder of our project. It starts from getting the incudes/header.php then the includes/classes/admin-class.php which contains a specific class to admins. FOr now it doesn't contain much functions but that could happen as the application grows.

The only function it contains now is loginAdmin($username, $password). This function checks if the username provided exists in our records. If yes, fetch the username and password of that admin. Then it will verify if the password provided is the same as the one in the database.

Dashboard.php

<?php
    // Start from getting the hader which contains some settings we need
    require_once 'includes/header.php';

    // Redirect visitor to the login page if he is trying to access
    // this page without being logged in
    if (!isset($_SESSION['admin_session']) )
    {
        session::destroy('admin_session');
        $commons->redirectTo(SITE_PATH.'index.php');
    }
?>
<html>
    <head>
        <title>Products Management System | Admin Panel</title>
        <link href='https://fonts.googleapis.com/css?family=Oswald:400,300' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
        <link rel="stylesheet" href="public/css/CreativeButtons/css/component.css">
        <link rel="stylesheet" href="public/css/style.css">
    </head>

    <body>
        <main class="container">
            <a href="https://lancecourse.com/en/howto/make-your-first-crud-with-php-case-of-a-product-management-system" class="btn btn-4 btn-4d icon-arrow-left">Return to tutorial</a>
            <div class="admin-pannel">

                <div class="dashboard">
                    <p><strong>Welcome to the dashboard !</strong></p>
                    <p>This place can be used to display a list of products or some expired products to warn the admins.</p>
                </div>
                <aside class="admin-menu">
                    <p>Connected as, <?= strip_tags($_SESSION['admin_session']) ?></p>
                    <ul>
                        <li><a href="">Dashboard</a></li>
                        <li><a href="">Add Admin</a></li>
                        <li><a href="">Add Product</a></li>
                        <li><a href="">List Products</a></li>
                        <li><a href="logout.php">Logout</a></li>
                    </ul>
                </aside>

                <div style="clear:both"> </div>
            </div>

            <footer>
                <?= date("Y") ?> &copy; lancecourse.com.com - Project by <a href="http://zooboole.me" target="_blank">zooboole</a> - Credit to <a href="http://tympanus.net/codrops/2013/06/13/creative-button-styles/" target="_blank">tympanus.net</a>
            </footer>
        </main>
    </body>
</html>

When the username and password are correct, a session is created for the admin, then redirected to this file. It requires the includes/header.php file then verifies if the user really got connected before getting here. If that's the case he stays on the dashboard otherwise he's redirected back to index.php.

Beside all this the I've created a simple menu which will allows, as admins, do take some actions in the feature. At the end of that menu you have the logout link which is used to log the admins out.

logout.php

<?php
    // Start from getting the header which contains some settings we need
    require_once 'includes/header.php';

    if (isset($_SESSION['admin_session']) )
    {
        session::destroy('admin_session');
        $commons->redirectTo(SITE_PATH.'index.php');
    }

This is the last file in the set. It also requires the header file, check if there is any admin session set, if yes, then destroy it and redirect the admin to the login page, index.php.

Conclusion

This is the end of this part. The demo is here, and use admin as username and password. I am not going to release my source code until the end of the series, because I want you to follow this tutorial very well. So far, all the source codes provided here can help you have the same as I do. Take your time to read each code carefully, and if you have any question just ask it under this tutorial, I promise I will do my best to provide you an adequate solution.

Check out the next part here.

Last updated 2024-01-11 UTC