Multi user Admin Panel in PHP with Source Code

Hey!

Are you frustrating of making admin panel for website?

Here I have something new for you….

  • index.php
<?php
require "lib/Core.php";
require PATH_LIB . "PAGE-top.php";?>
YOUR DASHBOARD HERE
<?php require PATH_LIB . "PAGE-bottom.php"; ?>
  • Login.php
<?php
// (A) INIT
require "lib/Core.php";
$_ISLOGIN = 1;
require PATH_LIB . "PAGE-top.php"; ?>

<!-- (B) JAVASCRIPT -->
<script>
function login () {
  admin.ajax({
    url : url.host + "ajax-session.php",
    data : {
      req : "in",
      email : document.getElementById("user_email").value,
      password : document.getElementById("user_password").value
    },
    ok : () => { location.reload(); }
  });
  return false;
}
</script>

<!-- (C) CSS -->
<style>
#login-form {
  max-width: 320px; margin: 0 auto; padding: 20px;
  background: #eee; border: 1px solid #ccc;
}
#login-form input { width: 100%; margin-top: 20px; }
</style>

<!-- (D) LOGIN FORM -->
<form id="login-form" onsubmit="return login();">
  <h1>LOGIN</h1>
  <input type="email" placeholder="Email" id="user_email" required />
  <input type="password" placeholder="Password" id="user_password" required />
  <input type="submit" value="Sign In"/>
</form>
<?php require PATH_LIB . "PAGE-bottom.php"; ?>
  • ajax-session.php
<?php
require "lib/Core.php";
if (isset($_POST["req"])) { switch ($_POST["req"]) {
  // (A) INVALID REQUEST
  default: exit("INVALID REQUEST");

  // (B) LOGIN
  case "in":
    // (B1) ALREADY SIGNED IN
    if (isset($_SESSION["user"])) { exit("OK"); }

    // (B2) VERIFY
    else {
      require PATH_LIB . "LIB-database.php";
      $DB = new DB();
      $user = $DB->fetch(
        "SELECT * FROM `users` WHERE `user_email`=?", [$_POST["email"]]
      );
      $pass = is_array($user);
      if ($pass) { $pass = password_verify($_POST["password"], $user["user_password"]); }
      if ($pass) {
        $_SESSION["user"] = [];
        foreach ($user as $k=>$v) { if ($k!="user_password") {
          $_SESSION["user"][$k] = $v;
        }}
        exit("OK");
      }
      exit("Invalid user/password");
    }

  // (C) LOGOUT
  case "out":
    unset($_SESSION["user"]);
    exit("OK");
}}
  • mypage.php
<?php
require "lib/Core.php";
require PATH_LIB . "PAGE-top.php"; ?>

<h1>MY PAGE</h1>
<p>Do something.</p>

<?php require PATH_LIB . "PAGE-bottom.php"; ?>

Now create two folder ‘lib’ & ‘public’ in that directory where you made that file.

  • core.php
<?php
// (A) ERROR HANDLING - CHANGE TO YOUR OWN
error_reporting(E_ALL & ~E_NOTICE);
ini_set("display_errors", 1);
// ini_set("log_errors", 1);
// ini_set("error_log", "PATH/error.log");

// (B) DATABASE SETTINGS - CHANGE TO YOUR OWN
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHARSET", "utf8");
define("DB_USER", "root");
define("DB_PASSWORD", "");

// (C) URL
define("URL_HOST", "http://localhost/"); // CHANGE TO YOUR OWN
define("URL_PUBLIC", URL_HOST . "public/");

// (D) FILE PATHS
define("PATH_LIB", __DIR__ . DIRECTORY_SEPARATOR);
define("PATH_BASE", dirname(PATH_LIB) . DIRECTORY_SEPARATOR);

// (E) START SESSION
session_start();
  • .htaccess
Deny from all
  • LIB-database.php
<?php
class DB {
  // (A) CONSTRUCTOR - CONNECT TO DATABASE
  private $pdo = null;
  private $stmt = null;
  public $error = "";
  function __construct () {
    try {
      $this->pdo = new PDO(
        "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET,
        DB_USER, DB_PASSWORD, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
      ]);
    } catch (Exception $ex) { exit($ex->getMessage()); }
  }

   // (B) DESTRUCTOR - CLOSE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }

  // (C) EXECUTE SQL QUERY
  function exec ($sql, $data=null) {
    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($data);
      return true;
    } catch (Exception $ex) {
      $this->error = $ex->getMessage();
      return false;
    }
  }

  // (D) FETCH
  function fetch ($sql, $data=null) {
    if ($this->exec($sql, $data) === false) { return false; }
    return $this->stmt->fetch();
  }
}
  • PAGE-bottom.php
      </main>
    </div>
  </body>
</html>
  • PAGE-top.php
<?php
// (A) LOGIN CHECK
$_ISADMIN = isset($_SESSION["user"]);
if (!$_ISADMIN && !isset($_ISLOGIN)) {
  header("Location: ".URL_HOST."login.php"); exit();
}
if ($_ISADMIN && isset($_ISLOGIN)) {
  header("Location: ".URL_HOST); exit();
} ?>
<!DOCTYPE html>
<html>
  <head>
    <title>ADMIN PANEL</title>
    <meta name="robots" content="noindex, nofollow">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2">
    <link href="<?=URL_PUBLIC?>admin.css" rel="stylesheet">
    <script>var url = {host:"<?=URL_HOST?>",public:"<?=URL_PUBLIC?>"};</script>
    <script async src="<?=URL_PUBLIC?>admin.js"></script>
  </head>
  <body>
    <!-- (B) NOW LOADING SPINNER -->
    <div id="page-loader">
      <img src="<?=URL_PUBLIC?>cube-loader.svg"/>
    </div>

    <?php if ($_ISADMIN) { ?>
    <!-- (C) SIDE BAR -->
    <nav id="page-sidebar">
      <a href="<?=URL_HOST?>pageA.php">
        <span class="ico">&#9879;</span> Module A
      </a>
      <a href="<?=URL_HOST?>pageB.php">
        <span class="ico">&#9880;</span> Module B
      </a>
    </nav>
    <?php } ?>

    <!-- (D) MAIN CONTENTS -->
    <div id="page-main">
      <?php if ($_ISADMIN) { ?>
      <!-- (D1) NAVIGATION BAR -->
      <nav id="page-nav">
        <div id="page-button-side" onclick="admin.sidebar();">&#9776;</div>
        <div id="page-button-out" onclick="admin.bye();">&#9747;</div>
      </nav>
      <?php } ?>

      <!-- (D2) PAGE CONTENTS -->
      <main id="page-contents">

Now the ‘public’ directory turn..

  • admin.css
/* (A) FONT & FORM */
* { font-family: Arial, sans-serif; }
h1, h2, h3, h4, h5, h6 { margin: 5px 0; }
button, input, textarea {
  box-sizing: border-box; padding: 10px;
}
button, input[type=button], input[type=submit] {
  color: #fff; background: #a92121;
  border: 0; cursor: pointer;
}

/* (B) NOW LOADING */
#page-loader {
  position: fixed; top: 0; left: 0; z-index: 999;
  width: 100vw; height: 100vh;
  background: rgba(0, 0, 0, 0.5);
  display: flex; align-items: center; justify-content: center;
  visibility: hidden; opacity: 0;
  transition: opacity 0.2s;
}
#page-loader.active { visibility: visible; opacity: 1; }

/* (C) PAGE LAYOUT */
body {
  padding: 0; margin: 0; display: flex;
  align-items: stretch; min-height: 100vh;
}
#page-sidebar { width: 200px; }
#page-main { flex-grow: 1; }

/* (D) SIDEBAR */
/* (D1) SIDEBAR ITSELF */
#page-sidebar {
  background: #353535;
  transition: width 0.2s;
}

/* (D2) SIDEBAR ITEMS */
#page-sidebar a {
  box-sizing: border-box; display: block;
  width: 100%; padding: 10px;
  color: #fff; text-decoration: none;
  border-bottom: 1px solid #555;
}
#page-sidebar a:hover { background: #222; }

/* (D3) SIDEBAR ICONS */
#page-sidebar .ico {
  display: inline-block; width:24px; text-align: center;
  font-size: 20px; line-height: 20px; color: #f48042;
}

/* (D4) HIDE SIDEBAR ON SMALL SCREEN */
@media (max-width: 768px) {
  #page-sidebar { width: 0; visibility: hidden; }
  #page-sidebar.active { width: 200px; visibility: visible; }
}

/* (E) PAGE MAIN */
/* (E1) MAIN SECTION ITSELF */
#page-main { background: #f7f9fa; }

/* (E2) NAVIGATION BAR */
#page-nav {
  position: relative; height: 50px;
  color: #fff; background: #474747;
}

/* (E3) NAVIGATION BAR BUTTONS */
#page-button-side, #page-button-out {
  position: absolute; top: 0;
  width: 50px; height: 50px; line-height: 50px;
  font-size: 28px; font-weight: bold; text-align: center;
  background: #87260e; cursor: pointer;
}
#page-button-side { display: none; left: 0; }
#page-button-out { right: 0; }
@media (max-width: 768px) {
  #page-button-side { display: block !important; }
}

/* (E4) CONTENTS */
#page-contents { padding: 20px; }
  • admin.js
var admin = {
	// (A) SHOW/HIDE "NOW LOADING" BLOCK
	loading : (show) => {
    var block = document.getElementById("page-loader");
    if (show) { block.classList.add("active"); }
    else { block.classList.remove("active"); }
	},

  // (B) TOGGLE SIDE BAR
	sidebar : () => {
    document.getElementById("page-sidebar").classList.toggle("active");
	},

  // (C) SIGN OFF
	bye : () => { if (confirm("Sign off?")) {
    admin.ajax({
      url : url.host + "ajax-session.php",
      data : { req : "out" },
      ok : () => { location.reload(); }
    });
  }},

  // (D) AJAX FETCH
  //  url : target url
  //  data : data to send
  //  ok : function to run on server "OK"
  ajax : (opt) => {
    // (D1) FORM DATA
    let data = new FormData();
    for (let [k, v] of Object.entries(opt.data)) { data.append(k, v); }

    // (D2) FETCH
    fetch(opt.url, { method:"POST", body:data })
    .then((res) => {
      if (res.status != 200) {
        alert(`Server ${res.status} error`);
        console.error(res);
      } else { return res.text(); }
    })
    .then((txt) => {
      if (txt != "OK") { alert(txt); }
      else { opt.ok(); }
    })
    .catch((err) => { console.error(err); });
  }
}
  • cube-loader.svg
<svg width="100px"  height="100px"  xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-cube" style="background: none;"><g transform="translate(25,25)"><rect ng-attr-x="{{config.dp}}" ng-attr-y="{{config.dp}}" ng-attr-width="{{config.blockSize}}" ng-attr-height="{{config.blockSize}}" ng-attr-fill="{{config.c1}}" x="-20" y="-20" width="40" height="40" fill="#fe0d02" transform="scale(1.3187 1.3187)"><animateTransform attributeName="transform" type="scale" calcMode="spline" values="1.5;1" keyTimes="0;1" dur="1s" keySplines="0 0.5 0.5 1" begin="-0.3s" repeatCount="indefinite"></animateTransform></rect></g><g transform="translate(75,25)"><rect ng-attr-x="{{config.dp}}" ng-attr-y="{{config.dp}}" ng-attr-width="{{config.blockSize}}" ng-attr-height="{{config.blockSize}}" ng-attr-fill="{{config.c2}}" x="-20" y="-20" width="40" height="40" fill="#feb200" transform="scale(1.00009 1.00009)"><animateTransform attributeName="transform" type="scale" calcMode="spline" values="1.5;1" keyTimes="0;1" dur="1s" keySplines="0 0.5 0.5 1" begin="-0.2s" repeatCount="indefinite"></animateTransform></rect></g><g transform="translate(25,75)"><rect ng-attr-x="{{config.dp}}" ng-attr-y="{{config.dp}}" ng-attr-width="{{config.blockSize}}" ng-attr-height="{{config.blockSize}}" ng-attr-fill="{{config.c3}}" x="-20" y="-20" width="40" height="40" fill="#043b42" transform="scale(1.01489 1.01489)"><animateTransform attributeName="transform" type="scale" calcMode="spline" values="1.5;1" keyTimes="0;1" dur="1s" keySplines="0 0.5 0.5 1" begin="0s" repeatCount="indefinite"></animateTransform></rect></g><g transform="translate(75,75)"><rect ng-attr-x="{{config.dp}}" ng-attr-y="{{config.dp}}" ng-attr-width="{{config.blockSize}}" ng-attr-height="{{config.blockSize}}" ng-attr-fill="{{config.c4}}" x="-20" y="-20" width="40" height="40" fill="#fe0d02" transform="scale(1.00442 1.00442)"><animateTransform attributeName="transform" type="scale" calcMode="spline" values="1.5;1" keyTimes="0;1" dur="1s" keySplines="0 0.5 0.5 1" begin="-0.1s" repeatCount="indefinite"></animateTransform></rect></g></svg>

At last you need to create a table in PHPMYSQL.

Here is SQL code.

-- (A) USERS TABLE
CREATE TABLE `users` (
  `user_id` int(11) NOT NULL,
  `user_email` varchar(255) NOT NULL,
  `user_name` varchar(255) NOT NULL,
  `user_password` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `users`
  ADD PRIMARY KEY (`user_id`),
  ADD UNIQUE KEY `user_email` (`user_email`),
  ADD KEY `user_name` (`user_name`);

ALTER TABLE `users`
  MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

-- (B) DEFAULT USER
-- EMAIL: JOHN@DOE.COM | PASSWORD: 123456
INSERT INTO `users` (`user_id`, `user_email`, `user_name`, `user_password`) VALUES
(1, 'john@doe.com', 'John Doe', '$2y$10$vZJy7y4uqQQTRN3zdi2RE.5ZJJzGEEPnzEjFXm4nEOx023XQ2Qe..');

Login Credentials:

Username: john@doe.com & Password: 123456

Leave a Reply

Your email address will not be published.