Basic Banking System

A small PHP and MySQL banking app: a money-transfer form with balance checks and a paginated transaction history.

ROLE
Developer
PERIOD
2021
DOMAIN
Student work

OVERVIEW

A small banking app in procedural PHP and MySQL. A form moves money between two accounts after checking the amount, both account numbers, and a 1,000 minimum balance, and a history page lists every transfer, newest first. There is no login: the project is about forms, server-side validation, and SQL writes.

ARRIVED AS

“A minimal banking flow for learning: move money between accounts and keep a record of every transfer.”

One of my first complete web applications, built in February 2021 as a task for The Sparks Foundation, which the app's footer credits. The scope is deliberately small: a home page, a form that transfers money between two accounts, and a history of every transfer. It was a way to learn the request-response cycle and how a page reads and writes a MySQL database.

WHAT I BUILT

  1. 01A transfer form (debit account, beneficiary account, amount) that validates the input, checks the balance, and moves the money.
  2. 02A transaction history page that lists every transfer, newest first, 100 per page.

WHAT CHANGED

  • A first pass at forms, server-side validation, and SQL writes against a real schema.

ARCHITECTURE

Four procedural PHP files over one MySQL database, with no framework:

  • index.php: the home page, linking to the transfer form and the history.
  • transfermoney.php: renders the transfer form and, on POST, runs the transfer.
  • transactionhistory.php: lists transfers, newest first, 100 per page.
  • database.php: opens the mysqli connection the other pages share.

The schema has an ACCOUNTS table (account number and balance) and a TRANSACTIONS table (debit account, beneficiary account, amount, time added).

Data flow

  1. The user fills in the transfer form and submits it back to transfermoney.php
  2. The amount must not be zero, the debit account must exist, and the sender must keep at least 1,000 after the transfer
  3. A row goes into TRANSACTIONS; if the beneficiary account does not exist, the insert fails and the page says so
  4. Two UPDATE queries debit the sender and credit the beneficiary
  5. The page shows success, or the error next to the field that failed

COMPONENTS

  • Transfer form

    Takes a debit account number, a beneficiary account number, and an amount, and marks the field that was wrong when a transfer fails.

  • Transfer logic

    Rejects a zero amount or an unknown account, refuses a transfer that would leave the sender below a 1,000 minimum balance, then records the transfer and updates both balances.

  • Transaction history

    Reads TRANSACTIONS newest first, 100 rows per page, and shows the account number on each side of every transfer.

Decisions, with the cost of each.

A decision without its trade-off is marketing. Each row says what was chosen, why, and what it gave up.

Procedural PHP over a framework

Wanted to understand the fundamentals before using abstractions like Laravel. This helped me appreciate what frameworks do under the hood.

AT THE COST OF

Each page mixes HTML, form handling, and SQL; nothing is shared between pages except the database connection.

Hand-written SQL instead of an ORM

Needed to learn SQL itself: an insert that looks up account ids with sub-selects, the balance updates, and a paginated history query.

AT THE COST OF

The queries are built by concatenating form input into SQL rather than using prepared statements, and the insert and the two balance updates run without a database transaction.

Minimal frontend styling

Focus was on the server side. Bootstrap's stylesheet and a few inline styles make it usable, not polished.

AT THE COST OF

No client-side validation: every check happens on the server, after the form is submitted.

LEARNED

  1. Validation belongs on the server

    Every check (zero amount, unknown account, minimum balance) runs in PHP after the form posts, so a request built by hand cannot skip it.

  2. Security fundamentals

    Concatenating form input into SQL, as this code does, leaves it open to SQL injection. Prepared statements are the fix.

  3. Why atomicity matters for money

    The transfer is three separate queries: an insert and two updates. If one fails partway, the balances and the history disagree. Wrapping them in one database transaction is what keeps them in step.