How to Create an Expenses and Incomes Tracker In PHP With MySQL Databse
In this PHP tutorial we will see how to create an Expense and Income Tracker web project with MySQL Database. 
It allows users to add, view, and delete transactions (expenses and incomes) and displays a summary of total expenses, total incomes, and the net balance.
The application uses a MySQL database to store transaction data, and the user interface is managed with HTML, CSS, and JavaScript for dynamic interactions.
What We Are Gonna Use In This Project:
- PHP Programming Language.- HTML, CSS, JavaScript.
- MySQL Database.
- Font-Awesome.
- VS Code Editor.
  
    
  
  
  
    
  
    
- VS Code Editor.
Project Source Code:
DatabaseConnection Class
<?php
// Define a class for managing database connections
class DatabaseConnection{
    // Private properties to store connection details
    private $host;
    private $username;
    private $password;
    private $database;
    private $charset;
    private $pdo; // PDO object for handling database connections
    // Constructor method to initialize connection details and establish connection
    public function __construct($host, $username, $password, $database, 
                                $charset = "utf8")
    {
        // Assign connection details to object properties
        $this->host = $host;
        $this->username = $username;
        $this->password = $password;
        $this->database = $database;
        $this->charset = $charset;
        $this->connect();
    }
    // Private method to establish database connection
    public function connect(){
        // Construct DSN (Data Source Name) for PDO connection
        $dsn = "mysql:host={$this->host}; dbname={$this->database}; 
                charset={$this->charset}";
        try{
            // Create a new PDO object and set attributes
            $this->pdo = new PDO($dsn, $this->username, $this->password);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
        }
        catch(PDOException $e){
            // If connection fails, output error message and terminate script
            die("Connection failed: " . $e->getMessage());
        }
    }
    // Method to execute a query with optional parameters
    public function query($sql, $params = []){
        // Prepare and execute the SQL statement with provided parameters
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        // Return the PDO statement object
        return $stmt;
    }
    // Method to fetch all rows from a query result with optional parameters
    public function fetchAll($sql, $params = []){
        // Execute the query and return all fetched rows
        $stmt = $this->query($sql, $params);
        return $stmt->fetchAll();
    }
}
?>
Transaction Class
<?php
class Transaction{
    private $id;
    private $type;
    private $description;
    private $amount;
    public function __construct($id, $type, $description, $amount){
        $this->id = $id;
        $this->type = $type;
        $this->description = $description;
        $this->amount = $amount;
    }
    public function getId(){ return $this->id; }
    public function getType(){ return $this->type; }
    public function getDescription(){ return $this->description; }
    public function getAmount(){ return $this->amount; }
}
?>
TransactionDAO Class
<?php
// Require the DatabaseConnection class file
require_once 'DatabaseConnection.php';
class TransactionDAO{
    public function __construct(){
        // Initialize a new DatabaseConnection object
        $this->db = new DatabaseConnection("localhost", "root", "", 
                                           "php_expense_income_db");
    }
    // Method to retrieve all transactions from the database
    public function getAllTransactions(){
        $sql = "SELECT * FROM `transaction_table`";
        return $this->db->fetchAll($sql);
    }
    // Method to add a new transaction to the database
    public function addTransaction(Transaction $transaction){
        // Define SQL query to insert a new row into the transaction_table
        $sql = "INSERT INTO `transaction_table`(`transaction_type`, `description`, 
                `amount`) VALUES (?, ?, ?)";
        // Define parameters for the SQL query
        $params = [$transaction->getType(), $transaction->getDescription(), 
                   $transaction->getAmount()];
        // Execute the SQL query using query method of DatabaseConnection
        $this->db->query($sql, $params);
    }
    // Method to delete a transaction from the database by its ID
    public function deleteTransaction($id){
        $sql = "DELETE FROM `transaction_table` WHERE id = ?";
        $this->db->query($sql, [$id]);
    }
}
?>
process_transaction.php File
<?php 
// Include necessary classes
require_once 'Transaction.php';
require_once 'TransactionDAO.php';
// Retrieve JSON data from the client
$jsonData = file_get_contents('php://input');
$data = json_decode($jsonData, true);
// Create a new Transaction object
$newTransaction = new Transaction(null, $data['type'], $data['description'], 
                                  $data['amount']);
// Create a new TransactionDAO
$transactionDAO = new TransactionDAO();
// Add the new transaction to the database
$transactionDAO->addTransaction($newTransaction);
// Send a response back to the client
echo json_encode(['status'=>'succes', 'message'=>'Transaction added successfully']);
?>
remove_transaction.php File
<?php
require_once 'TransactionDAO.php';
// Retrieve JSON data from the client
$jsonData = file_get_contents('php://input');
$data = json_decode($jsonData, true);
// Create a new Transaction object
$transactionDao = new TransactionDAO();
// Remove the transaction from the database
$transactionDao->deleteTransaction($data['transactionId']);
// Send a response back to the client
echo json_encode(['status'=>'succes', 'message'=>'Transaction removed successfully']);
?>
tracker_dashboard.php File
<?php
require_once 'TransactionDAO.php';
require_once 'TransactionValuesCalculation.php';
$trsDAO = new TransactionDAO();
// Retrieve all transactions
$transactions = $trsDAO->getAllTransactions();
$expenses = TransactionValuesCalculation::getTotalExpenses($transactions);
$incomes = TransactionValuesCalculation::getTotalIncomes($transactions);
$total = $incomes - $expenses;
if($total < 0){
    $formattedTotal = '-$'.number_format(abs($total), 2);
}
else{
    $formattedTotal = '+$'.number_format(abs($total), 2);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Expense And Income Tracker</title>
    <link rel="stylesheet" 
     href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="header">
        <span id="title">
            Expense and Income Tracker
        </span>
    </div>
    <div id="dashboard">
        <div class="data-panel" id="expense-panel"><i class="fas fa-shopping-cart"></i>
            <div>Expense: <?php echo '$'.number_format(abs($expenses), 2); ?></div>
        </div>
        <div class="data-panel" id="income-panel"><i class="fas fa-money-bill-wave">
            </i><div>Income: <?php echo '$'.number_format(abs($incomes), 2); ?></div>
        </div>
        <div class="data-panel" id="total-panel"><i class="fas fa-chart-pie"></i>
            <div>Total: <?php echo $formattedTotal; ?></div>
        </div>
        <div id="buttons">
            <button class="button" id="add-transaction"><i class="fas fa-plus"></i>
                 Add Transaction</button>
        </div>
        <table id="transaction-table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Type</th>
                    <th>Description</th>
                    <th id="amount-header">Amount<i class="fas fa-sort"></i></th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                <?php
                    foreach($transactions as $transaction){
                        // Define a class and style based on transaction type
                        $typeClass = ($transaction['transaction_type'] == 'Expense') 
                                    ? 'expense-type' : 'income-type';
                        echo'<tr>'.
                                '<td>'.$transaction['id'].'</td>'.
                                '<td><span class="'.$typeClass.'">'.
                                    $transaction['transaction_type'].'</span></td>'.
                                '<td>'.$transaction['description'].'</td>'.
                                '<td>$'.$transaction['amount'].'</td>'.
                                '<td class="remove-icon"><button class="delete-button"
                                     data-transaction-id="'.$transaction['id'].'">
                                    <i class="fas fa-trash"></i>Delete</button></td>'.
                            '</tr>';
                    }
                ?>
            </tbody>
    </div>
    <div id="add-transaction-dialog">
        <div id="dialog-title">Add Transaction</div>
        <div class="input-group">
            <label for="transaction-type">Type:</label>
            <select id="transaction-type">
                <option value="Expense">Expense</option>
                <option value="Income">Income</option>
            </select>
        </div>
        <div class="input-group">
            <label for="transaction-description">Description:</label>
            <input type="text" id="transaction-description">
        </div>
        <div class="input-group">
            <label for="transaction-amount">Amount:</label>
            <input type="text" id="transaction-amount">
        </div>
        <div class="button-group">
            <button class="button" id="add-transaction-button">Add</button>
            <button class="button cancel" id="cancel-transaction-button">
                    Cancel</button>
        </div>
    </div>
</body>
<script>
    // show dialog
    document.getElementById('add-transaction').addEventListener('click', function(){
        document.getElementById('add-transaction-dialog').style.display = 'block';
    });
    // hide dialog
    document.getElementById('cancel-transaction-button').addEventListener('click', 
        function(){
            document.getElementById('add-transaction-dialog').style.display = 'none';
    });
</script>
<script>
    // add transaction
    document.getElementById('add-transaction-button').addEventListener('click', 
     function(){
        // Retrieve input values
        var type = document.getElementById('transaction-type').value;
        var description = document.getElementById('transaction-description').value;
        var amount = document.getElementById('transaction-amount').value;
        // Create a new Transaction object
        var newTransaction = { type:type, description:description, amount:amount };
        // Send the data to the server using AJAX
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'process_transaction.php', true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4 && xhr.status == 200){
                location.reload();
                //console.log(xhr.responseText);
            }
        }
        // Convert the transaction object to JSON
        var jsonData = JSON.stringify(newTransaction);
        // Send the JSON data to the server
        xhr.send(jsonData);
    });
</script>
<script>
document.getElementById('amount-header').addEventListener('click', function(){
    // Get all table rows
    var tableRows = document.querySelectorAll('#transaction-table tbody tr');
    // Convert NodeList to an array for easier manipulation
    var rowsArray = Array.from(tableRows);
    // Check if the rows are already sorted in ascending order
    var ascending = this.classList.contains('asc');
    // Sort the rows based on the amount column
    rowsArray.sort(function(a,b){
        // Extract the amount values from the rows and convert them to numbers
        var amountA = parseFloat(a.children[3].textContent.replace('$',''));
        var amountB = parseFloat(b.children[3].textContent.replace('$',''));
        // Determine whether to sort in ascending or descending order
        if (ascending) { return amountA - amountB; /*Sort in ascending order*/ }
        else{ return amountB - amountA; /* Sort in descending order*/}
    });
    // Update the table with sorted rows
    var tbody= document.querySelector('#transaction-table tbody');
    // Clear the existing table body content
    tbody.innerHTML = '';
    rowsArray.forEach(function(row){ 
        // Append each row to the table body in the sorted order
        tbody.appendChild(row); 
    })
    // Toggle sorting direction class
    this.classList.toggle('asc');
});
</script>
<script>
// Add event listener for the "Delete" button
document.querySelectorAll('.delete-button').forEach(function(button){
    button.addEventListener('click', function(){
        // Get the transaction id
        var transactionId = this.getAttribute('data-transaction-id');
        // Confirm deletion (optional)
        var confirmDeletion = confirm(
                                'Are you sure you want to delete this transaction?');
        if(confirmDeletion){
            // Make AJAX request to remove the transaction
            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'remove_transaction.php', true);
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4 && xhr.status == 200){
                    location.reload();
                    //console.log(xhr.responseText);
                }
            }
            // Convert the transaction object to JSON
            var jsonData = JSON.stringify({transactionId:transactionId});
            // Send the JSON data to the server
            xhr.send(jsonData);
        }
    });
});
</script>
</html>













