Creating An Audit Trail/Logs in a Web App using PHP/OOP and Ajax Tutorial

In this tutorial, we will tackle about how to create an Audit Trail/Audit Log feature in a web application using PHP/OOP and jQuery Ajax. This feature is useful and a common feature for software or web applications. This is usually included in the project for an application that can be managed by multiple users. With this feature in your PHP Project, you can easily track or monitor the changes or actions made by the user.

Getting Started

In this tutorial, I will be using Bootrstrap for the design of the web app. Also, download jQuery for our ajax functions. I'll be using XAMPP as my local web server and database server.

Before we continue, please make sure that your Apache and MySQL.

Creating the Database

Open your PHPMyAdmin in browser and create new database naming audit_trailing. Next, navigate your database page into the SQL Tab and copy/paste the SQL Script below. Then, click the Go Button to execute the script.

  1. CREATE TABLE `logs` (
  2. `id` int(30) NOT NULL,
  3. `user_id` int(30) NOT NULL,
  4. `action_made` text NOT NULL,
  5.  
  6. CREATE TABLE `members` (
  7. `id` int(30) NOT NULL,
  8. `firstname` varchar(250) NOT NULL,
  9. `lastname` varchar(250) NOT NULL,
  10. `contact` varchar(50) NOT NULL,
  11. `address` text NOT NULL,
  12.  
  13.  
  14. INSERT INTO `members` (`id`, `firstname`, `lastname`, `contact`, `address`, `date_created`) VALUES
  15. (1, 'Clairy', 'Blake', '09123456789', 'Sample Address', '2021-10-07 11:51:27'),
  16. (2, 'John', 'Smith', '09123456789', 'Sample Address', '2021-10-07 11:55:00'),
  17. (5, 'Mikee', 'Williams', '09112655889', '23rd St. Here City', '2021-10-07 13:17:46');
  18.  
  19. CREATE TABLE `users` (
  20. `id` int(11) NOT NULL,
  21. `name` text NOT NULL,
  22. `username` text NOT NULL,
  23. `password` text NOT NULL,
  24. `date_created` datetime DEFAULT NULL
  25.  
  26. INSERT INTO `users` (`id`, `name`, `username`, `password`, `date_created`) VALUES
  27. (1, 'Administrator', 'admin', '0192023a7bbd73250516f069df18b500', '2021-10-07 03:59:25'),
  28. (2, 'john Smitn', 'jsmith', '1254737c076cf867dc53d60a0364f38e', '2021-10-07 03:59:25');
  29.  
  30. ALTER TABLE `logs`
  31. ADD PRIMARY KEY (`id`),
  32. ADD KEY `user_id` (`user_id`);
  33.  
  34. ALTER TABLE `members`
  35. ADD PRIMARY KEY (`id`);
  36.  
  37. ALTER TABLE `users`
  38. ADD PRIMARY KEY (`id`);
  39.  
  40. ALTER TABLE `members`
  41.  
  42. ALTER TABLE `users`
  43.  
  44. ALTER TABLE `logs`
  45.  
  46. ALTER TABLE `logs`
  47. ADD CONSTRAINT `logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;

Creating Our Database Connection

Create a new PHP File and copy/paste the script below. The script contains our PHP Class for database connection. Save the file as DBConnection.php.

  1. <?php
  2. if(!defined('host')) define('host',"localhost");
  3. if(!defined('username')) define('username',"root");
  4. if(!defined('password')) define('password',"");
  5. if(!defined('db_tbl')) define('db_tbl',"audit_trailing");
  6.  
  7. Class DBConnection{
  8. public $conn;
  9. function __construct(){
  10. $this->conn = new mysqli(host,username,password,db_tbl);
  11. if(!$this->conn){
  12. die("Database Connection Error. ".$this->conn->error);
  13. }
  14. }
  15. function __destruct(){
  16. $this->conn->close();
  17. }
  18. }
  19.  
  20. $db = new DBConnection();
  21. $conn= $db->conn;

Creating the Interface

The below codes are the scripts for our pages interfaces. Copy/Paste the scripts below and save the files according to the file name stated before the scripts.

login.php

This file contains the html scripts for our login page interface. The Ajax Script for the form submission is also included in this file.

  1. <?php
  2. session_start();
  3. if(isset($_SESSION['id']) && $_SESSION['id'] > 0){
  4. header("Location:./");
  5. exit;
  6. }
  7. require_once('./DBConnection.php');
  8. ?>
  9. <!DOCTYPE html>
  10. <html lang="en">
  11. <head>
  12. <meta charset="UTF-8">
  13. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  14. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  15. <title>LOGIN | Audit Trailing</title>
  16. <link rel="stylesheet" href="./css/bootstrap.min.css">
  17. <script src="./js/jquery-3.6.0.min.js"></script>
  18. <script src="./js/popper.min.js"></script>
  19. <script src="./js/bootstrap.min.js"></script>
  20. <script src="./js/script.js"></script>
  21. html, body{
  22. height:100%;
  23. }
  24. </style>
  25. </head>
  26. <body class="bg-dark bg-gradient">
  27. <div class="h-100 d-flex jsutify-content-center align-items-center">
  28. <div class='w-100'>
  29. <h3 class="py-5 text-center text-light">Audit Trailing/Audit Log</h3>
  30. <div class="card my-3 col-md-4 offset-md-4">
  31. <div class="card-body">
  32. <form action="" id="login-form">
  33. <center><small>Please Enter your system credential.</small></center>
  34. <div class="form-group">
  35. <label for="username" class="control-label">Username</label>
  36. <input type="text" id="username" autofocus name="username" class="form-control form-control-sm rounded-0" required>
  37. </div>
  38. <div class="form-group">
  39. <label for="password" class="control-label">Password</label>
  40. <input type="password" id="password" autofocus name="password" class="form-control form-control-sm rounded-0" required>
  41. </div>
  42. <div class="form-group d-flex w-100 justify-content-end">
  43. <button class="btn btn-sm btn-primary rounded-0 my-1">Login</button>
  44. </div>
  45. </form>
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. </body>
  51. $(function(){
  52. $('#login-form').submit(function(e){
  53. e.preventDefault();
  54. $('.pop_msg').remove()
  55. var _this = $(this)
  56. var _el = $('<div>')
  57. _el.addClass('pop_msg')
  58. _this.find('button').attr('disabled',true)
  59. _this.find('button[type="submit"]').text('Loging in...')
  60. $.ajax({
  61. url:'./Actions.php?a=login',
  62. method:'POST',
  63. data:$(this).serialize(),
  64. dataType:'JSON',
  65. error:err=>{
  66. console.log(err)
  67. _el.addClass('alert alert-danger')
  68. _el.text("An error occurred.")
  69. _this.prepend(_el)
  70. _el.show('slow')
  71. _this.find('button').attr('disabled',false)
  72. _this.find('button[type="submit"]').text('Save')
  73. },
  74. success:function(resp){
  75. if(resp.status == 'success'){
  76. _el.addClass('alert alert-success')
  77. setTimeout(() => {
  78. location.replace('./');
  79. }, 2000);
  80. }else{
  81. _el.addClass('alert alert-danger')
  82. }
  83. _el.text(resp.msg)
  84.  
  85. _el.hide()
  86. _this.prepend(_el)
  87. _el.show('slow')
  88. _this.find('button').attr('disabled',false)
  89. _this.find('button[type="submit"]').text('Save')
  90. }
  91. })
  92. })
  93. })
  94. </script>
  95. </html>
index.php

The code below is the script for our page template. It contains the top bar navigation, dynamic modal, and confirmation scripts.

  1. <?php
  2. session_start();
  3. if(!isset($_SESSION['id']) || (isset($_SESSION['id']) && $_SESSION['id'] <= 0)){
  4. header("Location:./login.php");
  5. exit;
  6. }
  7. require_once('./DBConnection.php');
  8. $page = isset($_GET['page']) ? $_GET['page'] : 'home';
  9. ?>
  10. <!DOCTYPE html>
  11. <html lang="en">
  12. <head>
  13. <meta charset="UTF-8">
  14. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  15. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  16. <title>Audit Trailing</title>
  17. <link rel="stylesheet" href="./fontawesome/css/all.min.css">
  18. <link rel="stylesheet" href="./css/bootstrap.min.css">
  19. <script src="./js/jquery-3.6.0.min.js"></script>
  20. <script src="./js/popper.min.js"></script>
  21. <script src="./js/bootstrap.min.js"></script>
  22. <link rel="stylesheet" href="./DataTables/datatables.min.css">
  23. <script src="./DataTables/datatables.min.js"></script>
  24. <script src="./fontawesome/js/all.min.js"></script>
  25. <script src="./js/script.js"></script>
  26. </style>
  27. </head>
  28. <body class="bg-light">
  29. <main>
  30. <nav class="navbar navbar-expand-lg navbar-dark bg-primary bg-gradient" id="topNavBar">
  31. <div class="container">
  32. <a class="navbar-brand" href="./">
  33. Audit Trailing
  34. </a>
  35. <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
  36. <span class="navbar-toggler-icon"></span>
  37. </button>
  38. <div class="collapse navbar-collapse" id="navbarNav">
  39. <ul class="navbar-nav">
  40. <li class="nav-item">
  41. <a class="nav-link <?php echo ($page == 'home')? 'active' : '' ?>" aria-current="page" href="./"><i class="fa fa-home"></i> Home</a>
  42. </li>
  43. <li class="nav-item">
  44. <a class="nav-link <?php echo ($page == 'logs')? 'active' : '' ?>" aria-current="page" href="./?page=logs"><i class="fa fa-th-list"></i> Audit Logs</a>
  45. </li>
  46. </ul>
  47. </div>
  48. <div>
  49. <?php if(isset($_SESSION['id'])): ?>
  50. <div class="dropdown">
  51. <button class="btn btn-secondary dropdown-toggle bg-transparent text-light border-0" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
  52. Hello <?php echo $_SESSION['name'] ?>
  53. </button>
  54. <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
  55. <li><a class="dropdown-item" href="././Actions.php?a=logout">Logout</a></li>
  56. </ul>
  57. </div>
  58. <?php endif; ?>
  59. </div>
  60. </div>
  61. </nav>
  62. <div class="container py-3" id="page-container">
  63. <?php
  64. if(isset($_SESSION['flashdata'])):
  65. ?>
  66. <div class="dynamic_alert alert alert-<?php echo $_SESSION['flashdata']['type'] ?>">
  67. <div class="float-end"><a href="javascript:void(0)" class="text-dark text-decoration-none" onclick="$(this).closest('.dynamic_alert').hide('slow').remove()">x</a></div>
  68. <?php echo $_SESSION['flashdata']['msg'] ?>
  69. </div>
  70. <?php unset($_SESSION['flashdata']) ?>
  71. <?php endif; ?>
  72. <?php
  73. include $page.'.php';
  74. ?>
  75. </div>
  76. </main>
  77. <div class="modal fade" id="uni_modal" role='dialog' data-bs-backdrop="static" data-bs-keyboard="true">
  78. <div class="modal-dialog modal-md modal-dialog-centered" role="document">
  79. <div class="modal-content">
  80. <div class="modal-header py-2">
  81. <h5 class="modal-title"></h5>
  82. </div>
  83. <div class="modal-body">
  84. </div>
  85. <div class="modal-footer py-1">
  86. <button type="button" class="btn btn-sm rounded-0 btn-primary" id='submit' onclick="$('#uni_modal form').submit()">Save</button>
  87. <button type="button" class="btn btn-sm rounded-0 btn-secondary" data-bs-dismiss="modal">Close</button>
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. <div class="modal fade" id="uni_modal_secondary" role='dialog' data-bs-backdrop="static" data-bs-keyboard="true">
  93. <div class="modal-dialog modal-md modal-dialog-centered" role="document">
  94. <div class="modal-content">
  95. <div class="modal-header py-2">
  96. <h5 class="modal-title"></h5>
  97. </div>
  98. <div class="modal-body">
  99. </div>
  100. <div class="modal-footer py-1">
  101. <button type="button" class="btn btn-sm rounded-0 btn-primary" id='submit' onclick="$('#uni_modal_secondary form').submit()">Save</button>
  102. <button type="button" class="btn btn-sm rounded-0 btn-secondary" data-bs-dismiss="modal">Close</button>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. <div class="modal fade" id="confirm_modal" role='dialog'>
  108. <div class="modal-dialog modal-md modal-dialog-centered" role="document">
  109. <div class="modal-content rounded-0">
  110. <div class="modal-header py-2">
  111. <h5 class="modal-title">Confirmation</h5>
  112. </div>
  113. <div class="modal-body">
  114. <div id="delete_content"></div>
  115. </div>
  116. <div class="modal-footer py-1">
  117. <button type="button" class="btn btn-primary btn-sm rounded-0" id='confirm' onclick="">Continue</button>
  118. <button type="button" class="btn btn-secondary btn-sm rounded-0" data-bs-dismiss="modal">Close</button>
  119. </div>
  120. </div>
  121. </div>
  122. </div>
  123. </body>
  124. </html>
home.php

This project is the script for our home page content. It contains our dummy data table.

  1. <div class="container py-5">
  2. <h3><b>Members List</b></h3>
  3. <div class="card">
  4. <div class="card-body">
  5. <div class="col-12 my-2 d-flex justify-content-end">
  6. <button class="btn btn-sm btn-primary rounded-0" id="add_new"><i class="fa fa-plus"></i> Add New</button>
  7. </div>
  8. <table class="table table-bordered table-striped table-hover">
  9. <tr>
  10. <th class="py-1 px-2">#</th>
  11. <th class="py-1 px-2">First Name</th>
  12. <th class="py-1 px-2">Last Name</th>
  13. <th class="py-1 px-2">Contact #</th>
  14. <th class="py-1 px-2">Address</th>
  15. <th class="py-1 px-2">Action</th>
  16. </tr>
  17. </thead>
  18. <?php
  19. $qry = $conn->query("SELECT * FROM members order by firstname asc, lastname asc");
  20. $i = 1;
  21. while($row=$qry->fetch_assoc()):
  22. ?>
  23. <tr>
  24. <td class="py-1 px-2"><?php echo $i++ ?></td>
  25. <td class="py-1 px-2"><?php echo $row['firstname'] ?></td>
  26. <td class="py-1 px-2"><?php echo $row['firstname'] ?></td>
  27. <td class="py-1 px-2"><?php echo $row['contact'] ?></td>
  28. <td class="py-1 px-2"><?php echo $row['address'] ?></td>
  29. <td class="py-1 px-2 text-center">
  30. <div class="btn-group" role="group">
  31. <button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle btn-sm rounded-0 py-0" data-bs-toggle='dropdown' aria-expanded="false" >
  32. Action
  33. </button>
  34. <ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
  35. <li><a class="dropdown-item view_data" href="javascript:void(0)" data-id="<?php echo $row['id'] ?>">View</a></li>
  36. <li><a class="dropdown-item edit_data" href="javascript:void(0)" data-id="<?php echo $row['id'] ?>">Edit</a></li>
  37. <li><a class="dropdown-item delete_data" href="javascript:void(0)" data-id="<?php echo $row['id'] ?>" data-name="<?php echo "[id={$row['id']}] ".$row['firstname'].' '.$row['lastname'] ?>">Delete</a></li>
  38. </ul>
  39. </div>
  40. </td>
  41. </tr>
  42. <?php endwhile; ?>
  43. <?php if($qry->num_rows <=0): ?>
  44. <tr>
  45. <th class="tex-center" colspan="6">No data to display.</th>
  46. </tr>
  47. <?php endif; ?>
  48. </tbody>
  49. </table>
  50. </div>
  51. </div>
  52. </div>
  53.  
  54. $(function(){
  55. $('#add_new').click(function(){
  56. uni_modal('New Member',"manage_member.php");
  57. })
  58. $('.edit_data').click(function(){
  59. uni_modal('Edit Member Details',"manage_member.php?id="+$(this).attr('data-id'));
  60. })
  61. $('.delete_data').click(function(){
  62. _conf("Ar you sure to delete <b>"+$(this).attr('data-name')+"</b> from member list?","delete_data",[$(this).attr('data-id')])
  63. })
  64. $('.view_data').click(function(){
  65. uni_modal('View Member Details',"view_member.php?id="+$(this).attr('data-id'));
  66. })
  67. })
  68. function delete_data($id){
  69. $('#confirm_modal button').attr('disabled',true)
  70. $.ajax({
  71. url:'./Actions.php?a=delete_member',
  72. method:'POST',
  73. data:{id:$id},
  74. dataType:'JSON',
  75. error:err=>{
  76. console.log(err)
  77. alert("An error occurred.")
  78. $('#confirm_modal button').attr('disabled',false)
  79. },
  80. success:function(resp){
  81. if(resp.status == 'success'){
  82. location.reload()
  83. }else{
  84. alert("An error occurred.")
  85. $('#confirm_modal button').attr('disabled',false)
  86. }
  87. }
  88. })
  89. }
  90. </script>
logs.php

The code below is the script which displays all the logs from database.

  1. <div class="container py-5">
  2. <div class="d-flex w-100">
  3. <h3 class="col-auto flex-grow-1"><b>Audit Trail</b></h3>
  4. <button class="btn btn-sm btn-primary rounded-0" type="button" onclick="location.reload()"><i class="fa fa-retweet"></i> Refresh List</button>
  5. </div>
  6. <hr>
  7. <div class="card">
  8. <div class="card-body">
  9. <table class="table table-bordered table-striped table-hover">
  10. <tr>
  11. <th class="py-1 px-2">#</th>
  12. <th class="py-1 px-2">DateTime</th>
  13. <th class="py-1 px-2">Username</th>
  14. <th class="py-1 px-2">Action Made</th>
  15. </tr>
  16. </thead>
  17. <?php
  18. $qry = $conn->query("SELECT l.*,u.username FROM `logs` l inner join users u on l.user_id = u.id order by unix_timestamp(l.`date_created`) asc");
  19. $i = 1;
  20. while($row=$qry->fetch_assoc()):
  21. ?>
  22. <tr>
  23. <td class="py-1 px-2"><?php echo $i++ ?></td>
  24. <td class="py-1 px-2"><?php echo date("M d, Y H:i",strtotime($row['date_created'])) ?></td>
  25. <td class="py-1 px-2"><?php echo $row['username'] ?></td>
  26. <td class="py-1 px-2"><?php echo $row['action_made'] ?></td>
  27. </tr>
  28. <?php endwhile; ?>
  29. <?php if($qry->num_rows <=0): ?>
  30. <tr>
  31. <th class="tex-center" colspan="4">No data to display.</th>
  32. </tr>
  33. <?php endif; ?>
  34. </tbody>
  35. </table>
  36. </div>
  37. </div>
  38. </div>
manage_member.php

This is the script for our member form which will be used in both adding and updating member's details. This will be shown in a modal.

  1. <?php
  2. require_once('./DBConnection.php');
  3. if(isset($_GET['id'])){
  4. $qry= $conn->query("SELECT * FROM members where id = '{$_GET['id']}'");
  5. if($qry->num_rows > 0){
  6. foreach($qry->fetch_array() as $k => $v){
  7. if(!is_numeric($k))
  8. $$k=$v;
  9. }
  10. }
  11. }
  12. ?>
  13. <div class="container-fluid">
  14. <form action="" id="member-form">
  15. <input type="hidden" name="id" value="<?php echo isset($id) ? $id : '' ?>">
  16. <div class="form-group">
  17. <label for="firstname" class="control-label">First Name</label>
  18. <input type="text" name="firstname" class="form-control form-control-sm rounded-0" value="<?php echo isset($firstname) ? $firstname : "" ?>" required>
  19. </div>
  20. <div class="form-group">
  21. <label for="lastname" class="control-label">Last Name</label>
  22. <input type="text" name="lastname" class="form-control form-control-sm rounded-0" value="<?php echo isset($lastname) ? $lastname : "" ?>" required>
  23. </div>
  24. <div class="form-group">
  25. <label for="contact" class="control-label">Contact #</label>
  26. <input type="text" name="contact" class="form-control form-control-sm rounded-0" value="<?php echo isset($contact) ? $contact : "" ?>" required>
  27. </div>
  28. <div class="form-group">
  29. <label for="address" class="control-label">Address</label>
  30. <textarea rows="3" name="address" class="form-control form-control-sm rounded-0" required><?php echo isset($address) ? $address : "" ?></textarea>
  31. </div>
  32. </form>
  33. </div>
  34. $(function(){
  35. $('#member-form').submit(function(e){
  36. e.preventDefault();
  37. $('.pop_msg').remove()
  38. var _this = $(this)
  39. var _el = $('<div>')
  40. _el.addClass('pop_msg')
  41. $('#uni_modal button').attr('disabled',true)
  42. $('#uni_modal button[type="submit"]').text('submitting form...')
  43. $.ajax({
  44. url:'./Actions.php?a=save_member',
  45. data: new FormData($(this)[0]),
  46. cache: false,
  47. contentType: false,
  48. processData: false,
  49. method: 'POST',
  50. type: 'POST',
  51. dataType: 'json',
  52. error:err=>{
  53. console.log(err)
  54. _el.addClass('alert alert-danger')
  55. _el.text("An error occurred.")
  56. _this.prepend(_el)
  57. _el.show('slow')
  58. $('#uni_modal button').attr('disabled',false)
  59. $('#uni_modal button[type="submit"]').text('Save')
  60. },
  61. success:function(resp){
  62. if(resp.status == 'success'){
  63. _el.addClass('alert alert-success')
  64. $('#uni_modal').on('hide.bs.modal',function(){
  65. location.reload()
  66. })
  67. if("<?php echo isset($enrollee_id) ?>" != 1)
  68. _this.get(0).reset();
  69. }else{
  70. _el.addClass('alert alert-danger')
  71. }
  72. _el.text(resp.msg)
  73.  
  74. _el.hide()
  75. _this.prepend(_el)
  76. _el.show('slow')
  77. $('#uni_modal button').attr('disabled',false)
  78. $('#uni_modal button[type="submit"]').text('Save')
  79. }
  80. })
  81. })
  82. })
  83. </script>
view_member.php

This is the script which displays the details of selected member. This will be shown in a modal.

  1. <?php
  2. require_once('./DBConnection.php');
  3. $qry= $conn->query("SELECT * FROM members where id = '{$_GET['id']}'");
  4. if($qry->num_rows > 0){
  5. foreach($qry->fetch_array() as $k => $v){
  6. if(!is_numeric($k))
  7. $$k=$v;
  8. }
  9. }
  10. ?>
  11. #uni_modal .modal-footer{
  12. display:none !important;
  13. }
  14. </style>
  15. <div class="container-fluid">
  16. <dl>
  17. <dt class="fs-6 text-muted">ID</dt>
  18. <dd class="fs-5 fw-bold"><?php echo $id ?></dd>
  19. <dt class="fs-6 text-muted">Name</dt>
  20. <dd class="fs-5 fw-bold"><?php echo $firstname." " .$lastname ?></dd>
  21. <dt class="fs-6 text-muted">Contact #</dt>
  22. <dd class="fs-5 fw-bold"><?php echo $contact ?></dd>
  23. <dt class="fs-6 text-muted">Address</dt>
  24. <dd class="fs-5 fw-bold"><?php echo $address ?></dd>
  25. </dl>
  26. <div class="col-12">
  27. <div class="w-100 d-flex justify-content-end">
  28. <button class="btn btn-sm btn-dark rounded-0" type="button" data-bs-dismiss="modal">Close</button>
  29. </div>
  30. </div>
  31. </div>
  32.  
  33. $(function(){
  34. $.ajax({
  35. url:'./Actions.php?a=save_log',
  36. method:'POST',
  37. data:{action_made:" viewed the data of <?php echo "[id={$id}]". $firstname.' '.$lastname ?>"},
  38. dataType:'json',
  39. error:err=>{
  40. console.log(err)
  41. },
  42. succuess:function(resp){
  43. if(resp == 1){
  44. console.log("Log successfully saved")
  45. }else{
  46. console.log("Log has failed to save.")
  47. }
  48. }
  49. })
  50. })
  51. </script>

Creating Our Custom Javascript Functions

The code below contains the scripts for our custome js/jquery functions of our dynamic modal and confirmation modal. In my case, I saved this file inside the js directory naming script.js. This file is included in the index.php file.

  1. window.uni_modal = function($title = '', $url = '', $size = "") {
  2. $.ajax({
  3. url: $url,
  4. error: err => {
  5. console.log()
  6. alert("An error occured")
  7. },
  8. success: function(resp) {
  9. if (resp) {
  10. $('#uni_modal .modal-title').html($title)
  11. $('#uni_modal .modal-body').html(resp)
  12. $('#uni_modal .modal-dialog').removeClass('large')
  13. $('#uni_modal .modal-dialog').removeClass('mid-large')
  14. $('#uni_modal .modal-dialog').removeClass('modal-md')
  15. if ($size == '') {
  16. $('#uni_modal .modal-dialog').addClass('modal-md')
  17. } else {
  18. $('#uni_modal .modal-dialog').addClass($size)
  19. }
  20. $('#uni_modal').modal({
  21. backdrop: 'static',
  22. keyboard: true,
  23. focus: true
  24. })
  25. $('#uni_modal').modal('show')
  26. }
  27. }
  28. })
  29. }
  30. window.uni_modal_secondary = function($title = '', $url = '', $size = "") {
  31. $.ajax({
  32. url: $url,
  33. error: err => {
  34. console.log()
  35. alert("An error occured")
  36. },
  37. success: function(resp) {
  38. if (resp) {
  39. $('#uni_modal_secondary .modal-title').html($title)
  40. $('#uni_modal_secondary .modal-body').html(resp)
  41. $('#uni_modal_secondary .modal-dialog').removeClass('large')
  42. $('#uni_modal_secondary .modal-dialog').removeClass('mid-large')
  43. $('#uni_modal_secondary .modal-dialog').removeClass('modal-md')
  44. if ($size == '') {
  45. $('#uni_modal_secondary .modal-dialog').addClass('modal-md')
  46. } else {
  47. $('#uni_modal_secondary .modal-dialog').addClass($size)
  48. }
  49. $('#uni_modal_secondary').modal({
  50. backdrop: 'static',
  51. keyboard: true,
  52. focus: true
  53. })
  54. $('#uni_modal_secondary').modal('show')
  55. }
  56. }
  57. })
  58. }
  59. window._conf = function($msg = '', $func = '', $params = []) {
  60. $('#confirm_modal #confirm').attr('onclick', $func + "(" + $params.join(',') + ")")
  61. $('#confirm_modal .modal-body').html($msg)
  62. $('#confirm_modal').modal('show')
  63. }

Creating the Main PHP Class

Lastly, copy/paste the source code below andd save it as Actions.php. This file is our main PHP Class which contains the action queries and the audit trail/log saving function.

  1. <?php
  2. require_once('DBConnection.php');
  3.  
  4. Class Actions extends DBConnection{
  5. function __construct(){
  6. parent::__construct();
  7. }
  8. function __destruct(){
  9. parent::__destruct();
  10. }
  11. function save_log($data=array()){
  12. // Data array paramateres
  13. // user_id = user unique id
  14. // action_made = action made by the user
  15.  
  16. if(count($data) > 0){
  17. extract($data);
  18. $sql = "INSERT INTO `logs` (`user_id`,`action_made`) VALUES ('{$user_id}','{$action_made}')";
  19. $save = $this->conn->query($sql);
  20. if(!$save){
  21. die($sql." <br> ERROR:".$this->conn->error);
  22. }
  23. }
  24. return true;
  25. }
  26. function login(){
  27. extract($_POST);
  28. $sql = "SELECT * FROM users where username = '{$username}' and `password` = '".md5($password)."' ";
  29. @$qry = $this->conn->query($sql)->fetch_array();
  30. if(!$qry){
  31. $resp['status'] = "failed";
  32. $resp['msg'] = "Invalid username or password.";
  33. }else{
  34. $resp['status'] = "success";
  35. $resp['msg'] = "Login successfully.";
  36. foreach($qry as $k => $v){
  37. if(!is_numeric($k))
  38. $_SESSION[$k] = $v;
  39. }
  40. $log['user_id'] = $qry['id'];
  41. $log['action_made'] = "Logged in the system.";
  42. // audit log
  43. $this->save_log($log);
  44. }
  45. return json_encode($resp);
  46. }
  47. function logout(){
  48. $log['user_id'] = $_SESSION['id'];
  49. $log['action_made'] = "Logged out.";
  50. // audit log
  51. $this->save_log($log);
  52. header("location:./");
  53. }
  54. function save_member(){
  55. extract($_POST);
  56. $data = "";
  57. foreach($_POST as $k => $v){
  58. if(!in_array($k,array('id'))){
  59. if(!empty($data)) $data .=", ";
  60. $data .= " `{$k}` = '{$v}' ";
  61. }
  62. }
  63. if(empty($id)){
  64. $sql = "INSERT INTO `members` set {$data}";
  65. }else{
  66. $sql = "UPDATE `members` set {$data} where id = '{$id}'";
  67. }
  68. $save = $this->conn->query($sql);
  69. if($save){
  70. $resp['status'] = 'success';
  71. $log['user_id'] = $_SESSION['id'];
  72. $member_id = empty($id) ? $this->conn->insert_id : $id ;
  73. if(empty($id)){
  74. $resp['msg'] = "New Member successfully added.";
  75. $log['action_made'] = " added [id={$member_id}] {$firstname} {$lastname} into the member list.";
  76. }else{
  77. $resp['msg'] = "Member successfully updated.";
  78. $log['action_made'] = " updated the details of [id={$member_id}] member.";
  79. }
  80. // audit log
  81. $this->save_log($log);
  82. }else{
  83. $resp['status'] = 'failed';
  84. $resp['msg'] = "Error saving member details. Error: ".$this->conn->error;
  85. $resp['sql'] = $sql;
  86. }
  87. return json_encode($resp);
  88. }
  89. function delete_member(){
  90. extract($_POST);
  91. $mem = $this->conn->query("SELECT * FROM members where id = '{$id}'")->fetch_array();
  92. $delete = $this->conn->query("DELETE FROM members where id = '{$id}'");
  93. if($delete){
  94. $resp['status'] = 'success';
  95. $resp['msg'] = 'Member successfully deleted.';
  96. $log['user_id'] = $_SESSION['id'];
  97. $log['action_made'] = " deleted [id={$mem['id']}] {$mem['firstname']} {$mem['lastname']} from member list.";
  98. $_SESSION['flashdata']['type'] = 'success';
  99. $_SESSION['flashdata']['msg'] = $resp['msg'];
  100.  
  101. // audit log
  102. $this->save_log($log);
  103. }else{
  104. $resp['status']='failed';
  105. $resp['msg']='Failed to delete member.';
  106. $resp['error']=$this->conn->error;
  107. }
  108. return json_encode($resp);
  109. }
  110. }
  111. $a = isset($_GET['a']) ?$_GET['a'] : '';
  112. $action = new Actions();
  113. switch($a){
  114. case 'login':
  115. echo $action->login();
  116. break;
  117. case 'logout':
  118. echo $action->logout();
  119. break;
  120. case 'save_member':
  121. echo $action->save_member();
  122. break;
  123. case 'delete_member':
  124. echo $action->delete_member();
  125. break;
  126. case 'save_log':
  127. $log['user_id'] = $_SESSION['id'];
  128. $log['action_made'] = $_POST['action_made'];
  129. echo $action->save_log($log);
  130. break;
  131. default:
  132. // default action here
  133. echo "No Action given";
  134. break;
  135. }

DEMO VIDEO

Sample Access

Username: admin/jsmith
Password: admin123/jsmith123

That's it! You can now test the simple web application that has an Audit Trail/Logs Feature that we created on your end. If you have encountered any errors, please review the scripts above. You can also download the working source code I created for this tutorial. Download button is located below this content.

I hope this PHP/OOP and jQuery Ajax Tutorial will help you with what you are looking for and you'll find this userful for your future PHP Projects.

Happy Coding :)

Comments

Submitted byORETNOMGFAN (not verified)on Thu, 06/09/2022 - 16:36

How to show search table on the data tables?

Add new comment