PHP Database Connectivity
                CMU529: Advanced Web Development - Session 7
                Birmingham Newman University
                Lecturer: James Williams
                Connecting PHP to MySQL, CRUD operations, prepared statements
                3-hour session • 22 slides • 2 interactive tasks
                
                    Session Timeline:
                    
                        - 10 min: Registration & waiting
 
                        - 20 min: Opening slides
 
                        - 45 min: Task 1
 
                        - 15 min: Break/Catch up
 
                        - 20 min: Secondary slides
 
                        - 45 min: Task 2
 
                        - Remaining: Self-study
 
                    
                 
            
            
            
                Learning Objectives
                
                    - Connect PHP to MySQL databases
 
                    - Perform CRUD operations with PHP
 
                    - Use prepared statements for security
 
                    - Handle database errors properly
 
                    - Build data-driven web applications
 
                
            
            
            
                Database Connection
                
                    Basic Database Connection:
                    
                    <?php
                    // Database configuration
                    $host = "localhost";
                    $username = "root";
                    $password = "";
                    $database = "ecommerce";
                    
                    // Create connection
                    try {
                      $pdo = new PDO("mysql:host=$host;dbname=$database", $username, $password);
                      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                      echo "Connected successfully";
                    } catch(PDOException $e) {
                      echo "Connection failed: " . $e->getMessage();
                    }
                    ?>
                
                
                    - PDO provides database abstraction
 
                    - Exception handling for errors
 
                    - Secure connection management
 
                
            
            
            
                Basic Queries
                
                    Simple SELECT Query:
                    
                    // Get all products
                    $stmt = $pdo->query("SELECT * FROM products");
                    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
                    
                    // Display products
                    foreach ($products as $product) {
                      echo "Name: " . $product['name'] . "<br>";
                      echo "Price: $" . $product['price'] . "<br>";
                    }
                    
                    // Get single product
                    $stmt = $pdo->query("SELECT * FROM products WHERE id = 1");
                    $product = $stmt->fetch(PDO::FETCH_ASSOC);
                
                
                    - Use query() for simple queries
 
                    - fetchAll() gets all results
 
                    - fetch() gets single result
 
                
            
            
            
                Prepared Statements
                
                    Secure Database Queries:
                    
                    // User registration with prepared statement
                    $stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");
                    
                    $username = $_POST['username'];
                    $email = $_POST['email'];
                    $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
                    
                    try {
                      $stmt->execute([$username, $email, $password]);
                      echo "User registered successfully";
                    } catch(PDOException $e) {
                      echo "Error: " . $e->getMessage();
                    }
                
                
                    - Prevents SQL injection attacks
 
                    - Separates data from SQL logic
 
                    - Improves performance with repeated queries
 
                
            
            
            
                INSERT Operations
                
                    Adding New Records:
                    
                    // Insert new product
                    $stmt = $pdo->prepare("INSERT INTO products (name, price, description) VALUES (?, ?, ?)");
                    
                    $name = "Laptop";
                    $price = 999.99;
                    $description = "High-performance laptop";
                    
                    try {
                      $stmt->execute([$name, $price, $description]);
                      $productId = $pdo->lastInsertId();
                      echo "Product added with ID: " . $productId;
                    } catch(PDOException $e) {
                      echo "Insert failed: " . $e->getMessage();
                    }
                
                
                    - Use prepared statements for security
 
                    - lastInsertId() gets the new record ID
 
                    - Always handle exceptions
 
                
            
            
            
                SELECT with Conditions
                
                    Filtered Queries:
                    
                    // Get products by category
                    $category = "electronics";
                    $stmt = $pdo->prepare("SELECT * FROM products WHERE category = ?");
                    $stmt->execute([$category]);
                    $products = $stmt->fetchAll();
                    
                    // Get expensive products
                    $minPrice = 500;
                    $stmt = $pdo->prepare("SELECT * FROM products WHERE price > ? ORDER BY price DESC");
                    $stmt->execute([$minPrice]);
                    $expensiveProducts = $stmt->fetchAll();
                    
                    // Search products
                    $searchTerm = "%laptop%";
                    $stmt = $pdo->prepare("SELECT * FROM products WHERE name LIKE ?");
                    $stmt->execute([$searchTerm]);
                
                
                    - Use WHERE clauses for filtering
 
                    - ORDER BY for sorting results
 
                    - LIKE for pattern matching
 
                
            
            
            
                UPDATE Operations
                
                    Modifying Records:
                    
                    // Update product price
                    $productId = 1;
                    $newPrice = 899.99;
                    
                    $stmt = $pdo->prepare("UPDATE products SET price = ? WHERE id = ?");
                    $stmt->execute([$newPrice, $productId]);
                    
                    // Update multiple fields
                    $stmt = $pdo->prepare("UPDATE products SET name = ?, price = ?, description = ? WHERE id = ?");
                    $stmt->execute(["Gaming Laptop", 1299.99, "High-end gaming laptop", $productId]);
                    
                    // Check if update was successful
                    if ($stmt->rowCount() > 0) {
                      echo "Product updated successfully";
                    } else {
                      echo "No product found with that ID";
                    }
                
                
                    - rowCount() shows affected rows
 
                    - Always use WHERE clause
 
                    - Update multiple fields in one query
 
                
            
            
            
                DELETE Operations
                
                    Removing Records:
                    
                    // Delete product by ID
                    $productId = 5;
                    $stmt = $pdo->prepare("DELETE FROM products WHERE id = ?");
                    $stmt->execute([$productId]);
                    
                    // Delete multiple records
                    $category = "old_products";
                    $stmt = $pdo->prepare("DELETE FROM products WHERE category = ?");
                    $stmt->execute([$category]);
                    
                    // Check deletion result
                    if ($stmt->rowCount() > 0) {
                      echo "Deleted " . $stmt->rowCount() . " products";
                    } else {
                      echo "No products found to delete";
                    }
                
                
                    - Always use WHERE clause
 
                    - Be careful with DELETE operations
 
                    - Check rowCount() for confirmation
 
                
            
            
            
                Error Handling
                
                    Database Error Management:
                    
                    try {
                      $stmt = $pdo->prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)");
                      $stmt->execute([$userId, $total]);
                      $orderId = $pdo->lastInsertId();
                    
                      // Insert order items
                      foreach ($items as $item) {
                        $stmt = $pdo->prepare("INSERT INTO order_items (order_id, product_id, quantity) VALUES (?, ?, ?)");
                        $stmt->execute([$orderId, $item['id'], $item['quantity']]);
                      }
                    
                      $pdo->commit();
                      echo "Order placed successfully";
                    } catch(PDOException $e) {
                      $pdo->rollback();
                      error_log("Database error: " . $e->getMessage());
                      echo "Order failed. Please try again.";
                    }
                
                
                    - Use try-catch for database operations
 
                    - Log errors for debugging
 
                    - Provide user-friendly messages
 
                
            
            
            
                Task 1: Basic CRUD Operations
                
                    Instructions:
                    
                        - Create a simple product management system with:
 
                        
                            - Database connection using PDO
 
                            - Add new products (INSERT)
 
                            - Display all products (SELECT)
 
                            - Update product details (UPDATE)
 
                            - Delete products (DELETE)
 
                        
                        - Use prepared statements for all queries
 
                        - Add proper error handling
 
                        - Create a simple HTML interface
 
                        - Test all CRUD operations
 
                    
                    Time: 45 minutes
                    This task will help you master basic database operations
                 
            
            
            
                Break Time
                
                    15 Minutes
                    Take a break, ask questions, or catch up on the previous task.
                    Next: Secondary slides and Task 2
                 
            
            
            
                Database Joins
                
                    Joining Tables:
                    
                    // Get products with category names
                    $stmt = $pdo->prepare("SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.id");
                    $stmt->execute();
                    $products = $stmt->fetchAll();
                    
                    // Get orders with user details
                    $stmt = $pdo->prepare("SELECT o.*, u.username FROM orders o INNER JOIN users u ON o.user_id = u.id WHERE o.user_id = ?");
                    $stmt->execute([$userId]);
                    $orders = $stmt->fetchAll();
                    
                    // Display joined data
                    foreach ($products as $product) {
                      echo "Product: " . $product['name'] . " - Category: " . $product['category_name'] . "<br>";
                    }
                
                
                    - LEFT JOIN includes all left table records
 
                    - INNER JOIN only includes matching records
 
                    - Use table aliases for clarity
 
                
            
            
            
                Aggregation Functions
                
                    Data Aggregation:
                    
                    // Count total products
                    $stmt = $pdo->query("SELECT COUNT(*) as total FROM products");
                    $result = $stmt->fetch();
                    echo "Total products: " . $result['total'] . "<br>";
                    
                    // Average product price
                    $stmt = $pdo->query("SELECT AVG(price) as avg_price FROM products");
                    $result = $stmt->fetch();
                    echo "Average price: $" . number_format($result['avg_price'], 2) . "<br>";
                    
                    // Products by category count
                    $stmt = $pdo->query("SELECT category, COUNT(*) as count FROM products GROUP BY category");
                    $categories = $stmt->fetchAll();
                    
                    foreach ($categories as $cat) {
                      echo $cat['category'] . ": " . $cat['count'] . " products<br>";
                    }
                
                
                    - COUNT() counts records
 
                    - AVG() calculates average
 
                    - GROUP BY groups results
 
                
            
            
            
                Pagination
                
                    Page Navigation:
                    
                    // Pagination variables
                    $page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
                    $limit = 10;
                    $offset = ($page - 1) * $limit;
                    
                    // Get total count
                    $stmt = $pdo->query("SELECT COUNT(*) as total FROM products");
                    $total = $stmt->fetch()['total'];
                    $totalPages = ceil($total / $limit);
                    
                    // Get products for current page
                    $stmt = $pdo->prepare("SELECT * FROM products ORDER BY name LIMIT ? OFFSET ?");
                    $stmt->execute([$limit, $offset]);
                    $products = $stmt->fetchAll();
                    
                    // Display pagination links
                    for ($i = 1; $i <= $totalPages; $i++) {
                      echo "<a href='?page=$i'>Page $i</a> ";
                    }
                
                
                    - LIMIT controls number of results
 
                    - OFFSET skips previous pages
 
                    - Calculate total pages for navigation
 
                
            
            
            
                Transactions
                
                    Transaction Management:
                    
                    try {
                      $pdo->beginTransaction();
                    
                      // Create order
                      $stmt = $pdo->prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)");
                      $stmt->execute([$userId, $total]);
                      $orderId = $pdo->lastInsertId();
                    
                      // Add order items
                      foreach ($cartItems as $item) {
                        $stmt = $pdo->prepare("INSERT INTO order_items (order_id, product_id, quantity) VALUES (?, ?, ?)");
                        $stmt->execute([$orderId, $item['id'], $item['quantity']]);
                        // Update stock
                        $stmt = $pdo->prepare("UPDATE products SET stock = stock - ? WHERE id = ?");
                        $stmt->execute([$item['quantity'], $item['id']]);
                      }
                    
                      $pdo->commit();
                      echo "Order completed successfully";
                    } catch(PDOException $e) {
                      $pdo->rollback();
                      echo "Order failed: " . $e->getMessage();
                    }
                
                
                    - beginTransaction() starts transaction
 
                    - commit() saves all changes
 
                    - rollback() undoes all changes
 
                
            
            
            
                Search Functionality
                
                    Product Search:
                    
                    // Search products
                    $search = isset($_GET['search']) ? trim($_GET['search']) : '';
                    
                    if (!empty($search)) {
                      $searchTerm = "%$search%";
                      $stmt = $pdo->prepare("SELECT * FROM products WHERE name LIKE ? OR description LIKE ? ORDER BY name");
                      $stmt->execute([$searchTerm, $searchTerm]);
                    } else {
                      $stmt = $pdo->query("SELECT * FROM products ORDER BY name");
                    }
                    
                    $products = $stmt->fetchAll();
                    
                    // Display search form
                    echo "<form method='GET'>";
                    echo "<input type='text' name='search' placeholder='Search products...'>";
                    echo "<button type='submit'>Search</button>";
                    echo "</form>";
                
                
                    - Use LIKE for pattern matching
 
                    - Search multiple fields
 
                    - Handle empty search terms
 
                
            
            
            
                Data Validation
                
                    Database-Level Validation:
                    
                    function checkEmailExists($email) {
                      global $pdo;
                      $stmt = $pdo->prepare("SELECT COUNT(*) FROM users WHERE email = ?");
                      $stmt->execute([$email]);
                      return $stmt->fetchColumn() > 0;
                    }
                    
                    function validateUniqueUsername($username) {
                      global $pdo;
                      $stmt = $pdo->prepare("SELECT COUNT(*) FROM users WHERE username = ?");
                      $stmt->execute([$username]);
                      return $stmt->fetchColumn() == 0;
                    }
                    
                    // Check before inserting
                    if (checkEmailExists($email)) {
                      echo "Email already exists";
                    } else {
                      // Proceed with registration
                    }
                
                
                    - Check for duplicate data
 
                    - Validate data integrity
 
                    - Prevent database conflicts
 
                
            
            
            
                Performance Optimization
                
                    Database Indexes:
                    
                    // Add indexes for better performance
                    CREATE INDEX idx_products_name ON products(name);
                    CREATE INDEX idx_products_price ON products(price);
                    CREATE INDEX idx_users_email ON users(email);
                    
                    // Optimized query with joins
                    $stmt = $pdo->prepare("SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.id WHERE p.name LIKE ? ORDER BY p.created_at DESC LIMIT ? OFFSET ?");
                
                
                    - Use indexes on frequently searched columns
 
                    - Implement pagination for large datasets
 
                    - Optimize image sizes and formats
 
                    - Use lazy loading for images
 
                
            
            
            
                Security Best Practices
                
                    Security Implementation:
                    
                    // Secure password hashing
                    $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
                    
                    // Input sanitization
                    $username = htmlspecialchars(trim($_POST['username']));
                    $email = filter_var(trim($_POST['email']), FILTER_SANITIZE_EMAIL);
                    
                    // CSRF protection
                    if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
                      die('CSRF token validation failed');
                    }
                
                
                    - Always use prepared statements
 
                    - Hash passwords with password_hash()
 
                    - Validate and sanitize all input
 
                    - Use HTTPS in production
 
                
            
            
            
                Task 2: Complete E-commerce Database System
                
                    Instructions:
                    
                        - Build a complete e-commerce database system with:
 
                        
                            - User registration and login forms
 
                            - Product management (CRUD operations)
 
                            - Shopping cart functionality
 
                            - Order processing system
 
                            - Search and filter functionality
 
                        
                        - Implement comprehensive validation
 
                        - Add security measures (CSRF, input sanitization)
 
                        - Include error handling and logging
 
                        - Add pagination for product listings
 
                        - Test all database operations
 
                    
                    Time: 45 minutes
                    This task will help you build a complete e-commerce database system
                 
            
            
            
                Session Summary
                
                    - Database integration is essential for dynamic web applications
 
                    - Prepared statements prevent SQL injection attacks
 
                    - CRUD operations enable data management
 
                    - Error handling improves application reliability
 
                    - Transactions ensure data consistency
 
                    - Performance optimization enhances user experience
 
                    - Security best practices protect against vulnerabilities
 
                    - Proper validation ensures data integrity
 
                
                
                    Next Session:
                    Session Management & User Authentication - User registration, login systems, and security