VU LIVE
📢 Browse Moaaz, Waqar Siddhu, Arslan & Tariq Papers — CS, MTH, ENG, MGT and more — Free study resources
All Pages Linked
Official Virtual Ustaad Academic Portal

CS619 E-Commerce Online Store Project — Complete Source Code with SRS, ERD and Viva Q&A

Virtual University of Pakistan — Verified Study Resources & Student Support

The CS619 E-Commerce Online Store is one of the most-often offered final year projects at Virtual University, and this guide builds it completely — in PHP and MySQL — so you can both learn and submit it. You start with the SRS: who uses the system, what it must do, and the rules (stock never goes below zero, prices are snapshotted into orders, and checkout runs inside a database transaction). Then you design the database with an ERD, write the code module by module with line-by-line explanations, test it with 20 test cases, and finish with viva questions and answers. The complete working code is included: login, dashboard, product and category management, catalogue with search, shopping cart, checkout, and order tracking. Follow the guide in order and you will have a working project and the understanding to defend it in the viva.

E-Commerce / Online Store — Learn + Build Guide

Course: CS619 Final Project, Virtual University of Pakistan Project: E-Commerce / Online Store (Top Project #3 — 9 projects in 4 semesters: Online Store, Web Based E-Commerce Site, B2C Online Store and Online Mobile Shop (Fall 2016); Online Mega Store, Online Jewellery Shop, PartsLo.pk (Spring 2025); Online PakBazar, Reloop Electronics Hub, SellPoint (Fall 2025); FashionHub (Spring 2026)) Stack: HTML, CSS, PHP, MySQL, WAMP Server, as stated in the official specification (Fall 2016 "Web Based E-Commerce Site": HTML, CSS, PHP, MySQL, WAMP Server; Fall 2016 "Online Store": PHP, MySQL). The Fall 2016 "Online Store" is described in the official list as: "Online shop where a business owner manages products, inventory and orders and customers browse, register and buy." The "Web Based E-Commerce Site" is an "online shop for phones, electronics and jewellery with a shopping cart and Bronze, Silver and Gold membership discounts." How to use this guide: build the project in the order of this guide — SRS, then Design, then Coding, then Testing, then Viva preparation. Every section first explains the idea in plain English, then shows the work. The complete code is in the files beside this guide; the Coding section explains each module and shows the important code with line-by-line notes.


1. Project overview — what you are building

A small shop keeps its records in notebooks: which products are in stock, who ordered what, and which orders are still waiting to be delivered. That is slow, stock counts go wrong, and orders get lost. This system replaces the notebooks with a web application — an online store.

What the system does

  • The shop owner (admin) adds products and categories, manages stock, sees all orders, and changes an order's status as it moves from pending to confirmed, shipped and delivered.
  • A customer registers (or logs in), browses the catalogue, searches by name or SKU, adds products to a shopping cart, checks out with a delivery address, and tracks their own orders.
  • The system itself works out order totals, generates order numbers (ORD-0001, ORD-0002, ...), and reduces stock the moment an order is placed — never below zero.

Who uses it

User What they can do
Admin (shop owner) Everything: products, categories, all orders, order status, dashboard
Customer Browse and search products, cart, checkout, view their own orders

Scope — what is in, and what is not

In scope: login with two roles, product catalogue and search, category management, product management, a database shopping cart, checkout with delivery details, order numbers, order items with price snapshots, stock decrease on order, order status workflow, dashboard with revenue and low-stock warnings, and a customer's own-orders page.

Out of scope (the official "Web Based E-Commerce Site" specification mentions membership discounts, but they are not built here): Bronze, Silver and Gold membership discounts, online card payment, email order confirmation, product images, and a customer "change password" page. These are listed as future improvements at the end of this guide. Saying clearly what you did NOT build — and why — is something viva examiners respect.


2. What you will learn (read this before you start coding)

You do not need to know everything below in advance. Learn each item when you reach the module that uses it.

Topic Where you use it
HTML forms (GET vs POST) Every page: login, add product, cart, checkout
PHP basics: variables, if/else, loops, functions Every file
PHP sessions ($_SESSION) Login: remembering who is logged in
MySQL: tables, primary keys, foreign keys schema.sql
PDO prepared statements (? placeholders) Every database query — this is how SQL injection is stopped
password_hash() / password_verify() Login
SQL transactions (beginTransaction / commit / rollBack) Checkout — five changes that must happen together
SQL joins (products + categories, orders + users, cart + products) Catalogue, cart, dashboard, orders
ON DUPLICATE KEY UPDATE Add to Cart — same product twice increases the quantity
DECIMAL(10, 2) for money Prices, totals, subtotals — never use FLOAT for money

Suggested order of work (about 4–6 weeks for one student)

  1. Week 1: install XAMPP, create the database, write the SRS (Section 3).
  2. Week 2: design the database and draw the ERD (Section 4).
  3. Weeks 3–4: write the code module by module (Section 5).
  4. Week 5: run the test cases (Section 6) and fix the bugs they find.
  5. Week 6: prepare the final report and practise the viva questions (Section 7).

3. SRS — Software Requirements Specification

This section is written so you can copy it into your SRS document (with your own project details) — it follows the sections VU expects in an SRS: purpose, scope, actors, functional requirements, non-functional requirements, and use cases.

3.1 Purpose

To build a web-based E-Commerce / Online Store that lets a small business sell products online: customers browse, search and buy, and the shop owner manages products, stock and orders, replacing manual notebooks with a system that is fast, searchable and always up to date.

3.2 Scope

The system covers the daily work of a small online shop: catalogue management, category management, a shopping cart, checkout with delivery details, order numbers, order tracking, stock control, and reports (dashboard counts, revenue, low stock, recent orders). It does not cover online card payments, membership discounts, email notifications, or product images.

3.3 Actors

  • Admin (shop owner): manages the whole system. There is one admin account to start with; more admin accounts can be added directly in the database.
  • Customer: a registered shopper. Customers browse products, fill a cart, place orders and view their own orders. Customers cannot change the catalogue or see other customers' orders.

3.4 Functional requirements

ID Requirement
FR1 The system shall let a user log in with a username and password. Wrong credentials shall be rejected with one general error message.
FR2 The system shall show different menus for admin and customer after login.
FR3 The admin shall add a product with name, SKU, description, price, stock and category. SKU shall be unique.
FR4 The admin shall edit and delete products. A product that appears in any past order shall not be deletable.
FR5 Any logged-in user shall search products by name or SKU and filter by category.
FR6 The admin shall add, rename and delete categories. Deleting a category shall not delete its products (they become "Uncategorised").
FR7 A customer shall add a product to the cart with a quantity. Adding the same product again shall increase its quantity, not add a second row.
FR8 The customer shall change quantities and remove products in the cart. The cart total shall be calculated from database prices.
FR9 The customer shall check out with name, delivery address, phone and payment method (Cash on Delivery or Bank Transfer).
FR10 On checkout, the system shall generate an order number (ORD-0001, ...), create the order and its items, decrease stock, and empty the cart — all in one transaction.
FR11 Checkout shall be refused when the stock of any cart product is below the ordered quantity.
FR12 Order items shall store a snapshot of the product name and unit price at order time, so later price changes never rewrite old orders.
FR13 The admin shall see all orders, filter them by status, and change an order's status (pending → confirmed → shipped → delivered, or cancelled).
FR14 A customer shall see only their own orders, with items, total and status.
FR15 The admin dashboard shall show: total products, total categories, total customers, total orders, total revenue (non-cancelled orders), orders waiting, low-stock products, and recent orders.

3.5 Non-functional requirements

ID Requirement
NFR1 Security: passwords shall be stored as hashes, never as plain text. All database queries shall use prepared statements. Pages shall check login on every request.
NFR2 Usability: every action shall show a success or error message. Forms shall keep the typed values when validation fails.
NFR3 Correctness: stock shall never go below 0 (enforced by the database CHECK and by the code). An order total shall always equal the sum of its items.
NFR4 Performance: the catalogue search and the dashboard shall answer in under 2 seconds with the sample data.
NFR5 Portability: the system shall run on XAMPP (Apache + MySQL) or WAMP on Windows without extra software.

3.6 Use cases

                    +-----------------------------+
                    |   E-Commerce / Online Store |
                    |                             |
   Admin ---------->|  Login                      |
     |              |  Manage Products            |
     |              |  Manage Categories          |
     |              |  View All Orders            |
     |              |  Change Order Status        |
     |              |  View Dashboard             |
                    |                             |
   Customer ------->|  Login                      |
                    |  Browse & Search Products   |
                    |  Add to Cart                |
                    |  Checkout                   |
                    |  View My Orders             |
                    +-----------------------------+
Use case Actor Main flow
Login Admin, Customer Enter username + password → system checks credentials → opens the right home page
Add Product Admin Fill the product form → system validates (SKU unique) → product appears in the catalogue
Search Products Admin, Customer Type a word / pick a category → system lists matching products
Add to Cart Customer Pick a product and quantity → system checks stock → cart shows the item
Checkout Customer Fill delivery details → system runs the stock checks → order created, stock reduced, cart emptied
Change Order Status Admin Pick an order and a new status → system updates it
View Dashboard Admin System shows counts, revenue, low stock and recent orders
View My Orders Customer System shows the customer's own orders with items and status

4. Design

4.1 Architecture

  Customer / Admin browser
        |
        |  HTTP (forms, links)
        v
  Apache web server (XAMPP / WAMP)
        |
        |  PHP files (this project)
        v
  MySQL database (ecommerce_db)

There is no framework and no JavaScript framework. That is a deliberate choice for a final-year project: every line of code is yours, you can explain all of it in the viva, and nothing is hidden inside a library.

Request flow for every page: config.php (session + database connection) → header.php (login check + menu) → page logic → footer.php.

4.2 ERD — Entity Relationship Diagram

  users (1) ───< cart (N) >─── (1) products
  users (1) ───< orders (N) ───< order_items (N) >─── (1) products
  categories (1) ───< products (N)

  +----------------+      +----------------+
  | users          |      | products       |
  | id (PK)        |      | id (PK)        |
  | name           |      | name           |
  | username       |      | sku (unique)   |
  | email          |      | description    |
  | password_hash  |      | price          |
  | role           |      | stock          |
  | phone, address |      | category_id FK |
  | status         |      +-------+--------+
Relationship Meaning
users 1 — N cart (user_id) One customer can have many cart rows; each cart row belongs to one customer.
products 1 — N cart (product_id) One product can sit in many customers' carts; each cart row is for one product.
users 1 — N orders (customer_id) One customer can place many orders; each order belongs to one customer.
orders 1 — N order_items (order_id) One order has many items; each item belongs to one order.
products 1 — N order_items (product_id) One product can appear in many orders; each item is for one product.
categories 1 — N products (category_id) One category holds many products; each product has at most one category.

4.3 Database design, table by table

users — everyone who can log in. role is admin or customer. password_hash holds a bcrypt hash, never the password itself. status is active or suspended; only the admin can change it (by editing the database — there is no member-management page in this project; see future improvements).

categories — just id and name (unique). Kept as a table instead of a text field so the category list is consistent and the "Add Product" form can offer a dropdown.

products — one row per product. sku is unique — the same product cannot be added twice by mistake. price is DECIMAL(10, 2): money must never be stored as FLOAT, because FLOAT rounds (Rs. 99.99 can become 99.98999...). stock is how many units are in the shop now. Two rules protect it: a database CHECK (stock >= 0, price >= 0) and the code, which only changes stock inside the checkout transaction (Section 5.6). category_id is a foreign key with ON DELETE SET NULL: deleting a category does not delete its products, it just clears their category.

cart — the shopping cart, stored in the database (not in the PHP session). One row per product per customer. UNIQUE (user_id, product_id) means the same product can appear only once per customer — adding it again increases the quantity (ON DUPLICATE KEY UPDATE). Storing the cart in the database (rather than $_SESSION) means the cart survives a logout and a browser restart — the customer finds their cart still there tomorrow. A CHECK (quantity > 0) stops a zero-quantity row.

orders — one row per order. order_no is generated by the system (ORD-0001, ...). total_amount is fixed at checkout time. status is pending, confirmed, shipped, delivered or cancelled. payment_method is cod (Cash on Delivery) or bank_transfer. The shipping name, address and phone are COPIED from the customer at checkout, so the order keeps the address it was sent to even if the customer changes their address later.

order_items — the products inside one order. product_name and unit_price are COPIES of the product's name and price at the moment of ordering (a snapshot). If the admin later changes a product's name or price, old orders still show what the customer actually paid. subtotal = unit_price × quantity. This snapshot design is a good example to quote in the viva when asked about a design decision.

Why the cart is a table, not a session array. A tempting design is $_SESSION['cart'] = [product_id => quantity]. The problem: the cart vanishes when the session ends (logout, browser closed, session timeout) and it lives only on one computer. A cart table is permanent, survives logout, and lets the admin (in a future version) see abandoned carts. The cost is one extra table — worth it.

4.4 UI flow (page map)

  index.php (Login)
      |
      +-- admin ----> dashboard.php
      |               |-- products.php <--> product_add / product_edit / product_delete
      |               |-- categories.php <--> category_add / category_edit / category_delete
      |               +-- orders.php <--> order_detail.php
      |
      +-- customer -> products.php (Shop — cards with Add to Cart)
                      |-- cart.php (view / update / remove)
                      |-- checkout.php --> order_detail.php
                      +-- my_orders.php <--> order_detail.php

4.5 Design decisions worth defending in the viva

  1. PDO prepared statements everywhere. User input is never pasted into SQL. This stops SQL injection completely.
  2. Transactions for checkout. Placing an order is five changes (order row, order items, stock decrease, cart cleared — plus the order-number generation). A transaction makes them atomic: all happen or none does.
  3. FOR UPDATE row lock on checkout. If two customers order the last unit at the same moment, the lock makes them wait in turn; the second one then sees 0 stock and is refused.
  4. Price snapshot in order_items. Old orders never change when prices change (see 4.3).
  5. Cart in the database, not the session (see 4.3).
  6. DECIMAL for money, never FLOAT. Exact rupees, no rounding.
  7. No framework. Every line is the student's own code and can be explained in the viva.

5. Coding — module by module

Each module is explained in plain English first, then the important code is shown with line-by-line notes. The full code is in the files beside this guide — read the module, then open its file and follow along.

5.1 Module 1 — Configuration and database connection (config.php)

What it does: every page needs two things — a session (to remember who is logged in) and a database connection. config.php provides both, plus small helper functions, so no page repeats that setup.

session_start();                       // (1)

define('DB_HOST', 'localhost');        // (2)
define('DB_NAME', 'ecommerce_db');
define('DB_USER', 'root');
define('DB_PASS', '');                 // XAMPP / WAMP default: root has no password

define('LOW_STOCK_LEVEL', 5);          // (3)
define('CURRENCY', 'Rs.');

$pdo = new PDO(                        // (4)
    'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4',
    DB_USER, DB_PASS,
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
     PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);

Line by line: (1) session_start() must run before any HTML is printed, or PHP shows a "headers already sent" error. (2) The database settings are constants, so they are written once and used everywhere. (3) The shop rules (low-stock warning at 5 units, currency "Rs.") are also constants — changing a rule means changing one line, not searching every file. (4) PDO is PHP's database layer. ERRMODE_EXCEPTION means a database error throws an exception instead of failing silently. FETCH_ASSOC means rows come back as ['name' => '...', 'price' => ...] arrays.

Helpers in the same file: e() escapes text before printing it (stops cross-site scripting); redirect() sends the browser elsewhere; flash() / showFlash() carry a one-time message to the next page; requireLogin() and requireAdmin() guard pages; nextOrderNo() generates ORD-0001, ORD-0002, ... from the highest existing number; formatPrice() prints 85000 as "Rs. 85,000".

5.2 Module 2 — Login and sessions (index.php, logout.php)

What it does: checks a username and password, then remembers the user in the session until logout.

$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ?');
$stmt->execute([$username]);
$user = $stmt->fetch();

if ($user && $user['status'] === 'active'
    && password_verify($password, $user['password_hash'])) {
    session_regenerate_id(true);
    $_SESSION['user_id']   = (int) $user['id'];
    $_SESSION['role']      = $user['role'];
    // ... then redirect to dashboard (admin) or the shop (customer)
}

Line by line: the ? in the query is a placeholder — the username is sent separately, so even a username like ' OR '1'='1 cannot change the SQL (this is the SQL-injection defence). password_verify() compares the typed password with the stored hash; the real password is never in the database. session_regenerate_id(true) gives the user a fresh session id after login, so an old session id cannot be reused. $_SESSION is a server-side array that survives from page to page — that is how the system "remembers" the login. The error message is always the same ("Invalid username or password") whether the username or the password was wrong, so an attacker cannot learn which usernames exist.

5.3 Module 3 — Product catalogue (products.php, product_add.php, product_edit.php, product_delete.php)

What it does: list and search products; add, edit and delete them (admin only). Customers see the same products as cards with a price, a stock note and an "Add to Cart" form.

Search and category filter (from products.php):

$conditions = [];
$params     = [];
if ($search !== '') {
    $conditions[] = '(p.name LIKE ? OR p.sku LIKE ?)';
    $like = '%' . $search . '%';
    $params[] = $like;
    $params[] = $like;
}
if ($categoryId !== null) {
    $conditions[] = 'p.category_id = ?';
    $params[] = $categoryId;
}
$where = $conditions ? ('WHERE ' . implode(' AND ', $conditions)) : '';

$stmt = $pdo->prepare(
    'SELECT p.*, c.name AS category_name
       FROM products p
  LEFT JOIN categories c ON c.id = p.category_id
      ' . $where . '
   ORDER BY p.name ASC'
);
$stmt->execute($params);

LEFT JOIN brings in the category name; a product with no category still appears (its category shows as "—"). LIKE '%word%' matches the word anywhere in the name or SKU. The WHERE clause is built only from the filters the user actually chose, and every value is bound as a parameter — the filter text itself can never reach the SQL as code.

Add (from product_add.php): a new product starts with the stock the admin types. SKU is unique; adding the same SKU twice fails with database error 23000, which the code catches and turns into the friendly message "A product with this SKU already exists."

Delete (from product_delete.php): two rules. First, deletion needs a confirmation page with a POST form, so a plain link can never delete anything. Second, a product that appears in any order cannot be deleted, because order_items references it and old orders must keep their history. The admin is told to set its stock to 0 instead.

5.4 Module 4 — Categories (categories.php, category_add.php, category_edit.php, category_delete.php)

What it does: list categories with a product count per category, and add, rename and delete them (admin only).

Renaming a category changes it everywhere at once, because products point to the category by id, not by name — that is why a separate table is better than typing the category name on every product.

Delete: the foreign key is ON DELETE SET NULL, so deleting a category never deletes its products — they become "Uncategorised". The confirmation page shows how many products that will affect, so the admin deletes with their eyes open.

5.5 Module 5 — Shopping cart (cart_add.php, cart.php)

What it does: keep the customer's chosen products in the cart table, and let the customer change quantities, remove items, and see the total.

Add to cart (from cart_add.php) — the one-query trick:

$stmt = $pdo->prepare(
    'INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)
     ON DUPLICATE KEY UPDATE quantity = quantity + VALUES(quantity)'
);
$stmt->execute([$userId, $productId, $quantity]);

Because of UNIQUE (user_id, product_id), adding a product that is already in the cart does not create a second row — MySQL runs the ON DUPLICATE KEY UPDATE part instead and increases the quantity. One query, no "check first, then insert" race. Before this, the code checks that the new total quantity is not more than the stock.

Cart total (from cart.php): the total is calculated from the prices in the database, never from values the browser sends — a customer cannot change a price by editing a form field, because prices are never in the form. Each quantity change is checked against the stock, and setting a quantity to 0 removes the row.

5.6 Module 6 — Checkout (checkout.php) — the most important module

What it does: turns the cart into an order, after stock checks, inside a transaction.

$pdo->beginTransaction();                              // (1)

// Re-read the cart inside the transaction and lock the rows.
foreach ($items as $item) {
    $stmt = $pdo->prepare('SELECT * FROM products WHERE id = ? FOR UPDATE');
    $stmt->execute([(int) $item['product_id']]);       // (2)
    $product = $stmt->fetch();
    if ((int) $product['stock'] < (int) $item['quantity']) {
        throw new Exception('Not enough stock for "' . $product['name'] . '".');
    }
    // ... remember product + quantity, add price x quantity to the total
}

// (3) Insert the order row with a generated order number.
$orderNo = nextOrderNo($pdo);
$stmt = $pdo->prepare(
    'INSERT INTO orders
        (order_no, customer_id, total_amount, status, payment_method,
         shipping_name, shipping_address, shipping_phone)
     VALUES (?, ?, ?, \'pending\', ?, ?, ?, ?)'
);
$stmt->execute([...]);
$orderId = (int) $pdo->lastInsertId();

// (4) Insert the order items (price snapshot) and decrease the stock.
foreach ($locked as $line) {
    $stmt = $pdo->prepare(
        'INSERT INTO order_items
            (order_id, product_id, product_name, unit_price, quantity, subtotal)
         VALUES (?, ?, ?, ?, ?, ?)'
    );
    $stmt->execute([$orderId, (int) $product['id'], $product['name'],
                    $price, $quantity, $price * $quantity]);

    $stmt = $pdo->prepare('UPDATE products SET stock = stock - ? WHERE id = ?');
    $stmt->execute([$quantity, (int) $product['id']]);
}

// (5) Empty the cart.
$stmt = $pdo->prepare('DELETE FROM cart WHERE user_id = ?');
$stmt->execute([$userId]);

$pdo->commit();                                         // (6)

Line by line: (1) beginTransaction() starts the transaction — from here, nothing is saved until commit(). (2) FOR UPDATE locks the product row: if another customer is ordering the same product at the same moment, they wait until this transaction finishes, then see the updated stock. (3) The order number comes from nextOrderNo() — the highest existing ORD number plus 1. (4) Each order item stores the product name and price as they are RIGHT NOW (the snapshot), and the stock goes down by the ordered quantity. (5) The cart is emptied — the products are now an order, not a cart. (6) commit() saves all five changes together. If any check throws an exception, the catch block calls rollBack() and nothing is saved — the database can never hold an order without its items, or stock taken without an order.

5.7 Module 7 — Orders and dashboard (orders.php, order_detail.php, my_orders.php, dashboard.php)

What it does: turns the stored rows into answers.

  • orders.php (admin) lists all orders, filterable by status. The filter is checked against an allowed list (all, pending, confirmed, shipped, delivered, cancelled) before it reaches the SQL — a made-up filter value can never change the query. The admin changes a status with a small form on each row; the new status is also checked against an allowed list.
  • order_detail.php shows one order with its items. An admin can open any order; a customer can open only their own — the check uses the customer id from the session, never from the URL, so a customer cannot view another customer's order by changing the id in the address bar. Prices shown here come from order_items (the snapshot), not from the products table.
  • my_orders.php takes the customer id from the session, never from the URL — for the same reason.
  • Dashboard counts are single COUNT(*) / SUM() queries — cheap and fast. Revenue is SUM(total_amount) over non-cancelled orders only (a cancelled order is not revenue). The low-stock list is WHERE stock <= LOW_STOCK_LEVEL (5), ordered by stock so the emptiest product is first.

6. Testing — test cases to run before submission

Run every case below against the working system and record Pass/Fail. A failed case is not a disaster — it is what testing is for; fix the bug, then run the case again.

ID Test Steps Expected result
TC-1 Login (admin) Log in as admin / admin123 Dashboard opens, admin menu shown
TC-2 Login (customer) Log in as customer / customer123 Shop catalogue opens, customer menu shown (no Dashboard link)
TC-3 Wrong password Log in as admin with a wrong password "Invalid username or password", still on login page
TC-4 Page guard Open dashboard.php without logging in Sent back to the login page
TC-5 Customer guard As a customer, open orders.php directly Sent back to the catalogue with an error
TC-6 Add product Add a product with 10 units in stock Product appears in the list with stock 10
TC-7 Duplicate SKU Add the same SKU again "A product with this SKU already exists"
TC-8 Search Search "Galaxy" Only the Samsung Galaxy A54 is listed
TC-9 Category filter Pick category "Fashion" Only Fashion products are listed
TC-10 Add to cart Add 2 x Samsung Galaxy A54 to the cart Cart shows 2 units, subtotal Rs. 170,000
TC-11 Add same product again Add 1 more of the same product Still one cart row, quantity now 3
TC-12 Add more than stock Try to add 11 units of a product with 10 in stock Refused: "Only 10 unit(s) ... are in stock"
TC-13 Update quantity Change a cart quantity to 1 Cart total updates
TC-14 Remove from cart Remove a product from the cart Product disappears, total updates
TC-15 Checkout Check out with 2 phones (Rs. 85,000 each) Order ORD-0001 created, total Rs. 170,000, status "pending"
TC-16 Stock decreases After TC-15, check the product Stock is 10 − 2 = 8
TC-17 Cart emptied After TC-15, open the cart Cart is empty
TC-18 Order detail snapshot Change the phone's price, then open the old order Old order still shows Rs. 85,000 per unit
TC-19 My Orders privacy As Ayesha, open the order of the customer account Sent back to My Orders with an error
TC-20 Delete with history Delete a product that appears in a past order Refused: product appears in past orders

Verification run (7 Nov 2026, PHP 8.3 + MariaDB 10.11): all 20 PHP files pass php -l; schema imports cleanly (6 tables, 3 users, 10 products); admin login reaches the dashboard; customer login reaches the catalogue; wrong password is rejected; unauthenticated dashboard redirects to login; a test order (2 phones) created ORD-0001 for Rs. 170,000, reduced stock from 10 to 8, and emptied the cart; the order detail page shows the placed-order message; the admin order list shows ORD-0001; a second customer is blocked from opening another customer's order. Test data was rolled back afterwards (database re-imported to the clean sample state).


7. Viva Q&A — questions the examiner is likely to ask

Q1. What does your project do? It is an online store: the shop owner manages products, categories and orders, and customers browse the catalogue, fill a shopping cart, check out, and track their own orders. The system generates order numbers and reduces stock when an order is placed.

Q2. Which technologies did you use, and why? HTML, CSS, PHP, MySQL and WAMP Server — the stack in the official project specification for the Fall 2016 "Web Based E-Commerce Site" (the Fall 2016 "Online Store" states PHP and MySQL). No framework, so all the code is mine and I can explain every line.

Q3. Show me your database design. Why six tables? users (login), categories, products (catalogue with price and stock), cart (one row per product per customer), orders (one row per order), order_items (the products inside an order, with a price snapshot). Six tables is enough because a cart row and an order item are the only things that connect a customer to a product. The ERD is in Section 4.2.

Q4. What is a foreign key? Give an example from your project. A column that must match a primary key in another table. order_items.order_id must be an id from orders — the database refuses an order item for an order that does not exist.

Q5. How do you stop SQL injection? Every query uses PDO prepared statements with ? placeholders. User input is sent as data, never pasted into the SQL string, so input like ' OR '1'='1 is treated as a plain value, not as SQL.

Q6. How are passwords stored? With password_hash(), which makes a bcrypt hash. The plain password is never stored. Login checks with password_verify().

Q7. Why is the cart a database table instead of a session array? Because a session cart vanishes on logout or session timeout, and it lives only on one computer. A cart table survives logout, survives a browser restart, and lets the shop see abandoned carts later.

Q8. What is a transaction, and where did you use one? A group of database changes that succeed together or fail together. Checkout is five changes (order row, order items, stock decrease, cart cleared — plus the order number), so they run in one transaction; if the stock update failed, the order row would be rolled back and the data would stay consistent.

Q9. Two customers order the last unit at the same moment. What happens? The first transaction locks the product row with FOR UPDATE. The second waits, then sees 0 stock and is refused with "Not enough stock". Without the lock, both could succeed and stock would go to −1.

Q10. A product's price changes. Why does an old order still show the old price? Because order_items stores a snapshot of the name and unit price at order time. The order shows what the customer actually paid, not the current catalogue price. This is the correct design for any shop.

Q11. Why DECIMAL and not FLOAT for prices? FLOAT stores approximate values and rounds — Rs. 99.99 can become 99.98999. DECIMAL(10, 2) stores exact rupees and paisa, so totals always add up exactly.

Q12. How does the system know who is logged in on each page? PHP sessions. After login, the user id, name and role are stored in $_SESSION. Every page includes config.php (which starts the session) and header.php (which calls requireLogin()).

Q13. How do you stop a customer seeing another customer's order? my_orders.php and the owner check in order_detail.php take the customer id from the session, never from the URL. Changing the id in the address bar cannot show another customer's order.

Q14. What would you add if you had more time? Bronze, Silver and Gold membership discounts (from the official specification), online card payment, email order confirmation, product images, a customer registration page, and a "change my password" page. Membership discounts would need a membership_tier on the user and a discount step in the checkout total.

Q15. What was the hardest bug you fixed? (The student should answer from their own testing — for example the checkout transaction rolling back when a stock check failed, or the ON DUPLICATE KEY UPDATE cart logic. Do not memorise an answer to this one; it must be true.)


8. Deliverables checklist (what to submit)

  • [ ] SRS document (Section 3 of this guide, written as your own document)
  • [ ] Design document (ERD, architecture, UI flow — Section 4)
  • [ ] Source code (all files in this folder, working)
  • [ ] Database file (schema.sql)
  • [ ] Test report (the test cases in Section 6, with Pass/Fail filled in)
  • [ ] Final report (what you built, how, and what you learned)
  • [ ] Presentation slides for the final viva
  • [ ] Demo video or live demo (run the system on your own laptop)

9. Common errors and fixes

Error / symptom Cause Fix
"Database connection failed" MySQL is not running, or schema.sql was not imported Start MySQL in XAMPP; import schema.sql in phpMyAdmin
"Table 'ecommerce_db.users' doesn't exist" The schema was imported into the wrong database, or not at all Re-import schema.sql (it creates the database itself)
"headers already sent" Something printed output before session_start() or header() Check for blank lines or spaces before <?php in the file; config.php must be included first
Login always fails The sample users were not imported, or the hash was changed Re-import schema.sql; check the user exists in phpMyAdmin
Stock goes below 0 Ordering without the stock check, or without the transaction Use checkout.php as written; never update stock by hand in phpMyAdmin
"A product with this SKU already exists" SKU is unique in the database This is correct behaviour — use a different SKU for a different product
Cart shows the wrong total The total was calculated from browser-sent prices The total must come from the database prices only, as in cart.php
Apache will not start Port 80 is already in use Stop the other program, or change Apache's port in the XAMPP control panel
Page shows nothing (white screen) A PHP error is hidden by the server settings Temporarily add error_reporting(E_ALL); ini_set('display_errors', '1'); at the top of config.php to see the message, then remove it

10. Future improvements

  1. Membership discounts — Bronze, Silver and Gold tiers from the official specification: a membership_tier column on users and a discount step in the checkout total (for example 0% / 5% / 10%).
  2. Online payment — card payment at checkout instead of Cash on Delivery only; store a payment reference on the order.
  3. Customer registration page — let shoppers create their own account instead of the admin creating it.
  4. Product images — an image filename per product and an upload form in the admin panel (images stored in the project folder).
  5. Email order confirmation — send the customer their order number and total when an order is placed.
  6. Change password page — let customers change their own password after first login instead of the admin setting it.
  7. Pagination — split the catalogue into pages when it grows past a few dozen products.

Frequently Asked Questions

  1. Which stack does this E-Commerce Online Store use? HTML, CSS, PHP, MySQL and WAMP Server, as stated in the official VU specification for the Fall 2016 "Web Based E-Commerce Site" (the Fall 2016 "Online Store" states PHP and MySQL). The demo accounts are admin/admin123 and customer/customer123.
  2. Does the code really work? Yes. It was runtime-verified: all 20 PHP files pass php -l, the schema imports cleanly into MySQL, the admin and customer logins work, and placing an order creates the order, empties the cart and reduces the stock (tested: 2 phones ordered, stock 10 → 8).
  3. Can I use this project for my CS619 final year project? Yes — it follows VU's own phases (SRS, design, coding, testing, viva). Change the sample data, add your own features from the future-improvements list, and write the SRS in your own words before submitting.

+-------+--------+ | N | 1 | | | 1 * +-------v--------+ +---v------------+ | categories | | orders | | id (PK) | | id (PK) | | name | | order_no | +--------------+ | customer_id FK | | total_amount | | status | | payment_method | | shipping_* | +-------+--------+ | 1 | * +----------------+ +---v----+| order_items | | || id (PK) | +--------+| order_id (FK) | | product_id (FK)| | product_name | | unit_price | | quantity | | subtotal | +----------------+ cart: id (PK), user_id (FK), product_id (FK), quantity, UNIQUE (user_id, product_id)

Relationships (read "1" as "one", "N" as "many"):

Comments

Advertisement
Advertisement

Tool