PHP Lesson 4: APIs, AJAX, Email & Building an E-commerce System

PHP Lesson 4: APIs, AJAX, Email & Building an E-commerce System

Oct 31, 2025 - 11:58
 0  129713
PHP Lesson 4: APIs, AJAX, Email & Building an E-commerce System

PHP Lesson 4: APIs, AJAX, Email & Building an E-commerce System

Welcome to Lesson 4! Now we're going to build professional-level PHP applications with APIs, real-time features, and payment processing.

Part 1: RESTful API Development

1.1 Building a Complete REST API

php
<?php
// api/config/Database.php
class Database {
    private $host = 'localhost';
    private $db_name = 'php_ecommerce';
    private $username = 'root';
    private $password = '';
    public $conn;

    public function getConnection() {
        $this->conn = null;
        try {
            $this->conn = new PDO(
                "mysql:host=" . $this->host . ";dbname=" . $this->db_name,
                $this->username, 
                $this->password
            );
            $this->conn->exec("set names utf8");
        } catch(PDOException $exception) {
            echo "Connection error: " . $exception->getMessage();
        }
        return $this->conn;
    }
}

// api/models/Product.php
class Product {
    private $conn;
    private $table = 'products';

    public $id;
    public $name;
    public $description;
    public $price;
    public $category_id;
    public $created_at;

    public function __construct($db) {
        $this->conn = $db;
    }

    // Read all products
    public function read() {
        $query = "SELECT p.*, c.name as category_name 
                 FROM " . $this->table . " p 
                 LEFT JOIN categories c ON p.category_id = c.id 
                 ORDER BY p.created_at DESC";
        
        $stmt = $this->conn->prepare($query);
        $stmt->execute();
        
        return $stmt;
    }

    // Read single product
    public function read_single() {
        $query = "SELECT p.*, c.name as category_name 
                 FROM " . $this->table . " p 
                 LEFT JOIN categories c ON p.category_id = c.id 
                 WHERE p.id = ? LIMIT 0,1";
        
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(1, $this->id);
        $stmt->execute();
        
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if($row) {
            $this->name = $row['name'];
            $this->description = $row['description'];
            $this->price = $row['price'];
            $this->category_id = $row['category_id'];
            $this->category_name = $row['category_name'];
            $this->created_at = $row['created_at'];
            return true;
        }
        return false;
    }

    // Create product
    public function create() {
        $query = "INSERT INTO " . $this->table . " 
                 SET name=:name, description=:description, price=:price, category_id=:category_id";
        
        $stmt = $this->conn->prepare($query);
        
        // Sanitize data
        $this->name = htmlspecialchars(strip_tags($this->name));
        $this->description = htmlspecialchars(strip_tags($this->description));
        $this->price = htmlspecialchars(strip_tags($this->price));
        $this->category_id = htmlspecialchars(strip_tags($this->category_id));
        
        // Bind data
        $stmt->bindParam(":name", $this->name);
        $stmt->bindParam(":description", $this->description);
        $stmt->bindParam(":price", $this->price);
        $stmt->bindParam(":category_id", $this->category_id);
        
        if($stmt->execute()) {
            return true;
        }
        return false;
    }

    // Update product
    public function update() {
        $query = "UPDATE " . $this->table . " 
                 SET name=:name, description=:description, price=:price, category_id=:category_id 
                 WHERE id=:id";
        
        $stmt = $this->conn->prepare($query);
        
        // Sanitize data
        $this->name = htmlspecialchars(strip_tags($this->name));
        $this->description = htmlspecialchars(strip_tags($this->description));
        $this->price = htmlspecialchars(strip_tags($this->price));
        $this->category_id = htmlspecialchars(strip_tags($this->category_id));
        $this->id = htmlspecialchars(strip_tags($this->id));
        
        // Bind data
        $stmt->bindParam(":name", $this->name);
        $stmt->bindParam(":description", $this->description);
        $stmt->bindParam(":price", $this->price);
        $stmt->bindParam(":category_id", $this->category_id);
        $stmt->bindParam(":id", $this->id);
        
        if($stmt->execute()) {
            return true;
        }
        return false;
    }

    // Delete product
    public function delete() {
        $query = "DELETE FROM " . $this->table . " WHERE id = ?";
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(1, $this->id);
        
        if($stmt->execute()) {
            return true;
        }
        return false;
    }
}

// api/config/Cors.php
class Cors {
    public function handleCors() {
        header("Access-Control-Allow-Origin: *");
        header("Content-Type: application/json; charset=UTF-8");
        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
        header("Access-Control-Max-Age: 3600");
        header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
        
        if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
            exit(0);
        }
    }
}

// api/products/index.php
header("Content-Type: application/json; charset=UTF-8");

require_once '../config/Database.php';
require_once '../config/Cors.php';
require_once '../models/Product.php';

$cors = new Cors();
$cors->handleCors();

$database = new Database();
$db = $database->getConnection();
$product = new Product($db);

$method = $_SERVER['REQUEST_METHOD'];
$input = json_decode(file_get_contents("php://input"), true);
$id = isset($_GET['id']) ? $_GET['id'] : null;

switch($method) {
    case 'GET':
        if ($id) {
            $product->id = $id;
            if($product->read_single()) {
                http_response_code(200);
                echo json_encode([
                    'id' => $id,
                    'name' => $product->name,
                    'description' => $product->description,
                    'price' => $product->price,
                    'category_id' => $product->category_id,
                    'category_name' => $product->category_name,
                    'created_at' => $product->created_at
                ]);
            } else {
                http_response_code(404);
                echo json_encode(['message' => 'Product not found.']);
            }
        } else {
            $stmt = $product->read();
            $num = $stmt->rowCount();
            
            if($num > 0) {
                $products_arr = array();
                $products_arr["data"] = array();
                
                while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                    extract($row);
                    $product_item = array(
                        "id" => $id,
                        "name" => $name,
                        "description" => $description,
                        "price" => $price,
                        "category_id" => $category_id,
                        "category_name" => $category_name,
                        "created_at" => $created_at
                    );
                    array_push($products_arr["data"], $product_item);
                }
                
                http_response_code(200);
                echo json_encode($products_arr);
            } else {
                http_response_code(404);
                echo json_encode(["message" => "No products found."]);
            }
        }
        break;
        
    case 'POST':
        if(!empty($input['name']) && !empty($input['price'])) {
            $product->name = $input['name'];
            $product->description = $input['description'] ?? '';
            $product->price = $input['price'];
            $product->category_id = $input['category_id'] ?? null;
            
            if($product->create()) {
                http_response_code(201);
                echo json_encode(["message" => "Product created."]);
            } else {
                http_response_code(503);
                echo json_encode(["message" => "Unable to create product."]);
            }
        } else {
            http_response_code(400);
            echo json_encode(["message" => "Unable to create product. Data is incomplete."]);
        }
        break;
        
    case 'PUT':
        if($id && !empty($input['name']) && !empty($input['price'])) {
            $product->id = $id;
            $product->name = $input['name'];
            $product->description = $input['description'] ?? '';
            $product->price = $input['price'];
            $product->category_id = $input['category_id'] ?? null;
            
            if($product->update()) {
                http_response_code(200);
                echo json_encode(["message" => "Product updated."]);
            } else {
                http_response_code(503);
                echo json_encode(["message" => "Unable to update product."]);
            }
        } else {
            http_response_code(400);
            echo json_encode(["message" => "Unable to update product. Data is incomplete."]);
        }
        break;
        
    case 'DELETE':
        if($id) {
            $product->id = $id;
            
            if($product->delete()) {
                http_response_code(200);
                echo json_encode(["message" => "Product deleted."]);
            } else {
                http_response_code(503);
                echo json_encode(["message" => "Unable to delete product."]);
            }
        } else {
            http_response_code(400);
            echo json_encode(["message" => "Unable to delete product. ID is missing."]);
        }
        break;
        
    default:
        http_response_code(405);
        echo json_encode(["message" => "Method not allowed."]);
        break;
}
?>

Part 2: AJAX Integration

2.1 Real-time Product Management with AJAX

php
<?php
// ajax_product_manager.php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
    <title>AJAX Product Manager</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }
        .container { display: grid; grid-template-columns: 1fr 2fr; gap: 30px; }
        .section { background: #f8f9fa; padding: 25px; border-radius: 10px; }
        .form-group { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 5px; }
        button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; }
        button:hover { background: #0056b3; }
        .product-item { background: white; padding: 15px; margin: 10px 0; border-radius: 5px; border-left: 4px solid #28a745; }
        .message { padding: 10px; margin: 10px 0; border-radius: 5px; }
        .success { background: #d4edda; color: #155724; }
        .error { background: #f8d7da; color: #721c24; }
        .loading { color: #6c757d; font-style: italic; }
        .actions { margin-top: 10px; }
        .actions button { margin-right: 5px; padding: 5px 10px; font-size: 0.9em; }
        .edit-btn { background: #ffc107; color: #212529; }
        .delete-btn { background: #dc3545; color: white; }
    </style>
</head>
<body>
    <h1>AJAX Product Manager</h1>
    
    <div class="container">
        <!-- Product Form -->
        <div class="section">
            <h2 id="form-title">Add New Product</h2>
            <form id="product-form">
                <input type="hidden" id="product-id">
                
                <div class="form-group">
                    <label>Product Name</label>
                    <input type="text" id="name" required>
                </div>
                
                <div class="form-group">
                    <label>Description</label>
                    <textarea id="description" rows="4"></textarea>
                </div>
                
                <div class="form-group">
                    <label>Price ($)</label>
                    <input type="number" id="price" step="0.01" min="0" required>
                </div>
                
                <div class="form-group">
                    <label>Category</label>
                    <select id="category_id">
                        <option value="1">Electronics</option>
                        <option value="2">Books</option>
                        <option value="3">Clothing</option>
                        <option value="4">Home & Garden</option>
                    </select>
                </div>
                
                <button type="submit" id="submit-btn">Add Product</button>
                <button type="button" id="cancel-btn" style="display: none; background: #6c757d;">Cancel</button>
            </form>
            
            <div id="form-message"></div>
        </div>
        
        <!-- Product List -->
        <div class="section">
            <h2>Products</h2>
            <div id="product-list">
                <div class="loading">Loading products...</div>
            </div>
        </div>
    </div>

    <script>
        const API_BASE = 'api/products/index.php';
        let editingId = null;

        // Load products on page load
        document.addEventListener('DOMContentLoaded', loadProducts);

        // Form submission
        document.getElementById('product-form').addEventListener('submit', function(e) {
            e.preventDefault();
            saveProduct();
        });

        // Cancel edit
        document.getElementById('cancel-btn').addEventListener('click', resetForm);

        async function loadProducts() {
            try {
                const response = await fetch(API_BASE);
                const data = await response.json();
                
                const productList = document.getElementById('product-list');
                
                if (data.data && data.data.length > 0) {
                    productList.innerHTML = data.data.map(product => `
                        <div class="product-item" id="product-${product.id}">
                            <h3>${product.name}</h3>
                            <p>${product.description}</p>
                            <p><strong>Price: $${product.price}</strong></p>
                            <p>Category: ${product.category_name}</p>
                            <div class="actions">
                                <button class="edit-btn" onclick="editProduct(${product.id})">Edit</button>
                                <button class="delete-btn" onclick="deleteProduct(${product.id})">Delete</button>
                            </div>
                        </div>
                    `).join('');
                } else {
                    productList.innerHTML = '<p>No products found.</p>';
                }
            } catch (error) {
                showMessage('Error loading products: ' + error.message, 'error');
            }
        }

        async function saveProduct() {
            const formData = {
                name: document.getElementById('name').value,
                description: document.getElementById('description').value,
                price: document.getElementById('price').value,
                category_id: document.getElementById('category_id').value
            };

            const submitBtn = document.getElementById('submit-btn');
            submitBtn.disabled = true;
            submitBtn.textContent = 'Saving...';

            try {
                let response;
                if (editingId) {
                    // Update existing product
                    response = await fetch(`${API_BASE}?id=${editingId}`, {
                        method: 'PUT',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(formData)
                    });
                } else {
                    // Create new product
                    response = await fetch(API_BASE, {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(formData)
                    });
                }

                const result = await response.json();
                
                if (response.ok) {
                    showMessage(result.message, 'success');
                    resetForm();
                    loadProducts();
                } else {
                    showMessage(result.message, 'error');
                }
            } catch (error) {
                showMessage('Error saving product: ' + error.message, 'error');
            } finally {
                submitBtn.disabled = false;
                submitBtn.textContent = editingId ? 'Update Product' : 'Add Product';
            }
        }

        async function editProduct(id) {
            try {
                const response = await fetch(`${API_BASE}?id=${id}`);
                const product = await response.json();
                
                if (response.ok) {
                    document.getElementById('product-id').value = product.id;
                    document.getElementById('name').value = product.name;
                    document.getElementById('description').value = product.description;
                    document.getElementById('price').value = product.price;
                    document.getElementById('category_id').value = product.category_id;
                    
                    editingId = product.id;
                    document.getElementById('form-title').textContent = 'Edit Product';
                    document.getElementById('submit-btn').textContent = 'Update Product';
                    document.getElementById('cancel-btn').style.display = 'inline-block';
                    
                    // Scroll to form
                    document.getElementById('product-form').scrollIntoView({ behavior: 'smooth' });
                }
            } catch (error) {
                showMessage('Error loading product: ' + error.message, 'error');
            }
        }

        async function deleteProduct(id) {
            if (!confirm('Are you sure you want to delete this product?')) {
                return;
            }

            try {
                const response = await fetch(`${API_BASE}?id=${id}`, {
                    method: 'DELETE'
                });

                const result = await response.json();
                
                if (response.ok) {
                    showMessage(result.message, 'success');
                    loadProducts();
                } else {
                    showMessage(result.message, 'error');
                }
            } catch (error) {
                showMessage('Error deleting product: ' + error.message, 'error');
            }
        }

        function resetForm() {
            document.getElementById('product-form').reset();
            document.getElementById('product-id').value = '';
            editingId = null;
            document.getElementById('form-title').textContent = 'Add New Product';
            document.getElementById('submit-btn').textContent = 'Add Product';
            document.getElementById('cancel-btn').style.display = 'none';
            document.getElementById('form-message').innerHTML = '';
        }

        function showMessage(message, type) {
            const messageDiv = document.getElementById('form-message');
            messageDiv.innerHTML = `<div class="message ${type}">${message}</div>`;
            setTimeout(() => {
                messageDiv.innerHTML = '';
            }, 5000);
        }
    </script>
</body>
</html>

Part 3: Email System with PHPMailer

3.1 Advanced Email System

php
<?php
// email/EmailService.php
require 'vendor/autoload.php'; // Install via: composer require phpmailer/phpmailer

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

class EmailService {
    private $mail;
    
    public function __construct() {
        $this->mail = new PHPMailer(true);
        $this->setup();
    }
    
    private function setup() {
        // Server settings
        $this->mail->isSMTP();
        $this->mail->Host = 'smtp.gmail.com';
        $this->mail->SMTPAuth = true;
        $this->mail->Username = 'your-email@gmail.com';
        $this->mail->Password = 'your-app-password';
        $this->mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $this->mail->Port = 587;
        
        // Sender
        $this->mail->setFrom('your-email@gmail.com', 'Your Store');
        $this->mail->isHTML(true);
    }
    
    public function sendWelcomeEmail($toEmail, $toName) {
        try {
            $this->mail->addAddress($toEmail, $toName);
            $this->mail->Subject = 'Welcome to Our Store!';
            
            $body = $this->getWelcomeTemplate($toName);
            $this->mail->Body = $body;
            $this->mail->AltBody = strip_tags($body);
            
            $this->mail->send();
            return ['success' => true, 'message' => 'Welcome email sent successfully'];
        } catch (Exception $e) {
            return ['success' => false, 'message' => "Email could not be sent. Error: {$this->mail->ErrorInfo}"];
        }
    }
    
    public function sendOrderConfirmation($toEmail, $toName, $orderDetails) {
        try {
            $this->mail->addAddress($toEmail, $toName);
            $this->mail->Subject = 'Order Confirmation - #' . $orderDetails['order_id'];
            
            $body = $this->getOrderTemplate($toName, $orderDetails);
            $this->mail->Body = $body;
            $this->mail->AltBody = strip_tags($body);
            
            $this->mail->send();
            return ['success' => true, 'message' => 'Order confirmation sent successfully'];
        } catch (Exception $e) {
            return ['success' => false, 'message' => "Email could not be sent. Error: {$this->mail->ErrorInfo}"];
        }
    }
    
    private function getWelcomeTemplate($name) {
        return "
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                body { font-family: Arial, sans-serif; background: #f4f4f4; padding: 20px; }
                .container { max-width: 600px; background: white; padding: 30px; border-radius: 10px; margin: 0 auto; }
                .header { background: #007bff; color: white; padding: 20px; text-align: center; border-radius: 5px; }
                .content { padding: 20px 0; }
                .button { background: #007bff; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; display: inline-block; }
                .footer { margin-top: 20px; padding-top: 20px; border-top: 1px solid #ddd; color: #666; }
            </style>
        </head>
        <body>
            <div class='container'>
                <div class='header'>
                    <h1>Welcome to Our Store!</h1>
                </div>
                <div class='content'>
                    <h2>Hello, $name!</h2>
                    <p>Thank you for joining our community. We're excited to have you on board!</p>
                    <p>As a welcome gift, here's a 10% discount on your first purchase:</p>
                    <h3 style='text-align: center; color: #007bff;'>WELCOME10</h3>
                    <p>Start shopping now and discover our amazing products:</p>
                    <p style='text-align: center;'>
                        <a href='http://yourstore.com/shop' class='button'>Start Shopping</a>
                    </p>
                </div>
                <div class='footer'>
                    <p>If you have any questions, feel free to contact our support team.</p>
                    <p>Best regards,<br>The Store Team</p>
                </div>
            </div>
        </body>
        </html>
        ";
    }
    
    private function getOrderTemplate($name, $orderDetails) {
        $itemsHtml = '';
        foreach ($orderDetails['items'] as $item) {
            $itemsHtml .= "
            <tr>
                <td>{$item['name']}</td>
                <td>{$item['quantity']}</td>
                <td>\${$item['price']}</td>
                <td>\${$item['total']}</td>
            </tr>
            ";
        }
        
        return "
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                body { font-family: Arial, sans-serif; background: #f4f4f4; padding: 20px; }
                .container { max-width: 600px; background: white; padding: 30px; border-radius: 10px; margin: 0 auto; }
                .header { background: #28a745; color: white; padding: 20px; text-align: center; border-radius: 5px; }
                .content { padding: 20px 0; }
                .order-table { width: 100%; border-collapse: collapse; margin: 20px 0; }
                .order-table th, .order-table td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
                .order-table th { background: #f8f9fa; }
                .total { font-size: 1.2em; font-weight: bold; color: #28a745; }
                .footer { margin-top: 20px; padding-top: 20px; border-top: 1px solid #ddd; color: #666; }
            </style>
        </head>
        <body>
            <div class='container'>
                <div class='header'>
                    <h1>Order Confirmed!</h1>
                </div>
                <div class='content'>
                    <h2>Hello, $name!</h2>
                    <p>Thank you for your order. We're processing it and will notify you when it ships.</p>
                    
                    <h3>Order Details:</h3>
                    <table class='order-table'>
                        <tr>
                            <th>Product</th>
                            <th>Quantity</th>
                            <th>Price</th>
                            <th>Total</th>
                        </tr>
                        $itemsHtml
                        <tr>
                            <td colspan='3' style='text-align: right;'><strong>Subtotal:</strong></td>
                            <td>\${$orderDetails['subtotal']}</td>
                        </tr>
                        <tr>
                            <td colspan='3' style='text-align: right;'><strong>Shipping:</strong></td>
                            <td>\${$orderDetails['shipping']}</td>
                        </tr>
                        <tr>
                            <td colspan='3' style='text-align: right;'><strong>Total:</strong></td>
                            <td class='total'>\${$orderDetails['total']}</td>
                        </tr>
                    </table>
                    
                    <h3>Shipping Address:</h3>
                    <p>{$orderDetails['shipping_address']}</p>
                </div>
                <div class='footer'>
                    <p>Order ID: #{$orderDetails['order_id']}</p>
                    <p>If you have any questions about your order, contact our support team.</p>
                    <p>Best regards,<br>The Store Team</p>
                </div>
            </div>
        </body>
        </html>
        ";
    }
}

// Usage example
if ($_POST['action'] == 'send_welcome') {
    $emailService = new EmailService();
    $result = $emailService->sendWelcomeEmail($_POST['email'], $_POST['name']);
    echo json_encode($result);
}
?>

Part 4: Complete E-commerce System

4.1 E-commerce Application with Cart & Checkout

php
<?php
// ecommerce/index.php
session_start();

class Cart {
    public function __construct() {
        if (!isset($_SESSION['cart'])) {
            $_SESSION['cart'] = [];
        }
    }
    
    public function addItem($productId, $quantity = 1, $productData = null) {
        if (isset($_SESSION['cart'][$productId])) {
            $_SESSION['cart'][$productId]['quantity'] += $quantity;
        } else {
            $_SESSION['cart'][$productId] = [
                'quantity' => $quantity,
                'product' => $productData
            ];
        }
    }
    
    public function updateQuantity($productId, $quantity) {
        if (isset($_SESSION['cart'][$productId])) {
            if ($quantity <= 0) {
                $this->removeItem($productId);
            } else {
                $_SESSION['cart'][$productId]['quantity'] = $quantity;
            }
        }
    }
    
    public function removeItem($productId) {
        unset($_SESSION['cart'][$productId]);
    }
    
    public function getCart() {
        return $_SESSION['cart'];
    }
    
    public function getTotal() {
        $total = 0;
        foreach ($_SESSION['cart'] as $item) {
            $total += $item['product']['price'] * $item['quantity'];
        }
        return $total;
    }
    
    public function getItemCount() {
        $count = 0;
        foreach ($_SESSION['cart'] as $item) {
            $count += $item['quantity'];
        }
        return $count;
    }
    
    public function clear() {
        $_SESSION['cart'] = [];
    }
}

class Order {
    private $db;
    
    public function __construct($db) {
        $this->db = $db;
    }
    
    public function create($userId, $cart, $shippingInfo) {
        try {
            $this->db->beginTransaction();
            
            // Create order
            $query = "INSERT INTO orders (user_id, total, status, shipping_address) 
                     VALUES (:user_id, :total, 'pending', :shipping_address)";
            $stmt = $this->db->prepare($query);
            $stmt->bindParam(':user_id', $userId);
            $stmt->bindParam(':total', $shippingInfo['total']);
            $stmt->bindParam(':shipping_address', $shippingInfo['address']);
            $stmt->execute();
            
            $orderId = $this->db->lastInsertId();
            
            // Create order items
            $query = "INSERT INTO order_items (order_id, product_id, quantity, price) 
                     VALUES (:order_id, :product_id, :quantity, :price)";
            $stmt = $this->db->prepare($query);
            
            foreach ($cart as $productId => $item) {
                $stmt->bindParam(':order_id', $orderId);
                $stmt->bindParam(':product_id', $productId);
                $stmt->bindParam(':quantity', $item['quantity']);
                $stmt->bindParam(':price', $item['product']['price']);
                $stmt->execute();
            }
            
            $this->db->commit();
            return $orderId;
            
        } catch (Exception $e) {
            $this->db->rollBack();
            return false;
        }
    }
}

// Initialize cart
$cart = new Cart();

// Handle cart actions
if (isset($_POST['action'])) {
    switch ($_POST['action']) {
        case 'add_to_cart':
            $cart->addItem($_POST['product_id'], $_POST['quantity'], [
                'name' => $_POST['product_name'],
                'price' => $_POST['product_price'],
                'image' => $_POST['product_image']
            ]);
            break;
            
        case 'update_cart':
            $cart->updateQuantity($_POST['product_id'], $_POST['quantity']);
            break;
            
        case 'remove_from_cart':
            $cart->removeItem($_POST['product_id']);
            break;
            
        case 'clear_cart':
            $cart->clear();
            break;
    }
    
    header('Location: ' . $_SERVER['PHP_SELF']);
    exit;
}

// Sample products
$products = [
    1 => ['id' => 1, 'name' => 'Wireless Headphones', 'price' => 99.99, 'image' => 'headphones.jpg'],
    2 => ['id' => 2, 'name' => 'Smart Watch', 'price' => 199.99, 'image' => 'watch.jpg'],
    3 => ['id' => 3, 'name' => 'Laptop Backpack', 'price' => 49.99, 'image' => 'backpack.jpg'],
    4 => ['id' => 4, 'name' => 'USB-C Cable', 'price' => 19.99, 'image' => 'cable.jpg']
];
?>

<!DOCTYPE html>
<html>
<head>
    <title>PHP E-commerce Store</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f8f9fa; }
        .header { background: #343a40; color: white; padding: 15px 0; }
        .container { max-width: 1200px; margin: 0 auto; padding: 0 20px; }
        .nav { display: flex; justify-content: space-between; align-items: center; }
        .cart-info { background: #007bff; padding: 10px 15px; border-radius: 20px; }
        .products { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 30px; margin: 40px 0; }
        .product-card { background: white; border-radius: 10px; padding: 20px; text-align: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        .product-image { width: 100%; height: 200px; object-fit: cover; border-radius: 5px; }
        .product-price { color: #28a745; font-size: 1.2em; font-weight: bold; margin: 10px 0; }
        .btn { background: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; }
        .btn-success { background: #28a745; }
        .cart-section { background: white; padding: 30px; border-radius: 10px; margin: 40px 0; }
        .cart-table { width: 100%; border-collapse: collapse; }
        .cart-table th, .cart-table td { padding: 15px; text-align: left; border-bottom: 1px solid #ddd; }
        .quantity-input { width: 60px; padding: 5px; text-align: center; }
        .checkout-btn { background: #28a745; color: white; padding: 15px 30px; border: none; border-radius: 5px; cursor: pointer; font-size: 1.1em; }
    </style>
</head>
<body>
    <div class="header">
        <div class="container">
            <div class="nav">
                <h1>PHP Store</h1>
                <div class="cart-info">
                    Cart: <?= $cart->getItemCount() ?> items - $<?= number_format($cart->getTotal(), 2) ?>
                </div>
            </div>
        </div>
    </div>

    <div class="container">
        <!-- Products Grid -->
        <h2>Featured Products</h2>
        <div class="products">
            <?php foreach ($products as $product): ?>
            <div class="product-card">
                <img src="images/<?= $product['image'] ?>" alt="<?= $product['name'] ?>" class="product-image">
                <h3><?= $product['name'] ?></h3>
                <div class="product-price">$<?= number_format($product['price'], 2) ?></div>
                <form method="POST">
                    <input type="hidden" name="action" value="add_to_cart">
                    <input type="hidden" name="product_id" value="<?= $product['id'] ?>">
                    <input type="hidden" name="product_name" value="<?= $product['name'] ?>">
                    <input type="hidden" name="product_price" value="<?= $product['price'] ?>">
                    <input type="hidden" name="product_image" value="<?= $product['image'] ?>">
                    <input type="number" name="quantity" value="1" min="1" style="width: 60px; margin-right: 10px;">
                    <button type="submit" class="btn">Add to Cart</button>
                </form>
            </div>
            <?php endforeach; ?>
        </div>

        <!-- Shopping Cart -->
        <div class="cart-section">
            <h2>Shopping Cart</h2>
            <?php if (empty($cart->getCart())): ?>
                <p>Your cart is empty.</p>
            <?php else: ?>
                <table class="cart-table">
                    <thead>
                        <tr>
                            <th>Product</th>
                            <th>Price</th>
                            <th>Quantity</th>
                            <th>Total</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($cart->getCart() as $productId => $item): ?>
                        <tr>
                            <td><?= $item['product']['name'] ?></td>
                            <td>$<?= number_format($item['product']['price'], 2) ?></td>
                            <td>
                                <form method="POST" style="display: inline;">
                                    <input type="hidden" name="action" value="update_cart">
                                    <input type="hidden" name="product_id" value="<?= $productId ?>">
                                    <input type="number" name="quantity" value="<?= $item['quantity'] ?>" min="1" class="quantity-input">
                                    <button type="submit" class="btn">Update</button>
                                </form>
                            </td>
                            <td>$<?= number_format($item['product']['price'] * $item['quantity'], 2) ?></td>
                            <td>
                                <form method="POST" style="display: inline;">
                                    <input type="hidden" name="action" value="remove_from_cart">
                                    <input type="hidden" name="product_id" value="<?= $productId ?>">
                                    <button type="submit" class="btn" style="background: #dc3545;">Remove</button>
                                </form>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                    <tfoot>
                        <tr>
                            <td colspan="3" style="text-align: right;"><strong>Total:</strong></td>
                            <td><strong>$<?= number_format($cart->getTotal(), 2) ?></strong></td>
                            <td></td>
                        </tr>
                    </tfoot>
                </table>
                
                <div style="margin-top: 20px; text-align: center;">
                    <form method="POST" style="display: inline; margin-right: 10px;">
                        <input type="hidden" name="action" value="clear_cart">
                        <button type="submit" class="btn" style="background: #6c757d;">Clear Cart</button>
                    </form>
                    <button class="checkout-btn" onclick="window.location.href='checkout.php'">Proceed to Checkout</button>
                </div>
            <?php endif; ?>
        </div>
    </div>
</body>
</html>

Key Concepts Covered:

  1. RESTful APIs: CRUD operations, proper HTTP status codes

  2. AJAX Integration: Real-time updates without page reloads

  3. Email System: Professional email templates with PHPMailer

  4. E-commerce Features: Shopping cart, order management

  5. Security: Input validation, CORS handling

  6. Database Design: Proper relationships and transactions

Practice Exercises:

  1. Add user authentication to the API

  2. Implement product search and filtering

  3. Add payment gateway integration (Stripe/PayPal)

  4. Create an admin dashboard for order management

  5. Implement product reviews and ratings

Next Lesson Preview:

In Lesson 5, we'll cover:

  • Advanced security practices

  • Performance optimization

  • Caching strategies

  • Deployment and DevOps

  • Building a complete SaaS application

You're now building professional-grade PHP applications with modern features! These skills are directly applicable to real-world web development projects.

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow

MA Hussain Amjad Hussain: Architect of Truth in the Realm of Fact In the intricate tapestry of human experience, where shadow often meets light, Amjad Hussain stands as a dedicated chronicler of reality. His is a world built on the unshakeable foundations of fact, a pursuit he undertakes with the dual tools of a journalist's discerning eye and a writer's compelling narrative skill.