PHP Lesson 3: Databases, File Handling & Object-Oriented Programming
PHP Lesson 3: Databases, File Handling & Object-Oriented Programming
Welcome to Lesson 3! Now we're moving into more advanced PHP concepts that will let you build robust, real-world applications.
Part 1: MySQL Database Integration
1.1 Setting Up Database Connection
First, let's create a proper database connection class:
<?php
class Database {
private $host = 'localhost';
private $db_name = 'php_app';
private $username = 'root';
private $password = '';
private $conn;
public function connect() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host=" . $this->host . ";dbname=" . $this->db_name,
$this->username,
$this->password
);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Connection Error: " . $e->getMessage();
}
return $this->conn;
}
}
// Create database and table setup script (run once)
function setupDatabase() {
try {
$temp_conn = new PDO("mysql:host=localhost", "root", "");
$temp_conn->exec("CREATE DATABASE IF NOT EXISTS php_app");
$temp_conn->exec("USE php_app");
$sql = "CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role ENUM('user', 'admin') DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
$temp_conn->exec($sql);
$sql = "CREATE TABLE IF NOT EXISTS posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
user_id INT,
image_path VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)";
$temp_conn->exec($sql);
// Insert sample data
$temp_conn->exec("INSERT IGNORE INTO users (name, email, password, role) VALUES
('Admin User', 'admin@example.com', '" . password_hash('admin123', PASSWORD_DEFAULT) . "', 'admin'),
('John Doe', 'john@example.com', '" . password_hash('password123', PASSWORD_DEFAULT) . "', 'user')
");
echo "Database setup completed successfully!";
} catch(PDOException $e) {
echo "Setup Error: " . $e->getMessage();
}
}
// Uncomment the line below to run setup (run once only)
// setupDatabase();
?>
1.2 User Registration & Login System with Database
<?php session_start(); require_once 'Database.php'; class User { private $db; private $table = 'users'; public function __construct() { $database = new Database(); $this->db = $database->connect(); } // Register new user public function register($name, $email, $password) { try { // Check if email already exists $query = "SELECT id FROM " . $this->table . " WHERE email = :email"; $stmt = $this->db->prepare($query); $stmt->bindParam(':email', $email); $stmt->execute(); if ($stmt->rowCount() > 0) { return "Email already exists!"; } // Insert new user $query = "INSERT INTO " . $this->table . " (name, email, password) VALUES (:name, :email, :password)"; $stmt = $this->db->prepare($query); $hashed_password = password_hash($password, PASSWORD_DEFAULT); $stmt->bindParam(':name', $name); $stmt->bindParam(':email', $email); $stmt->bindParam(':password', $hashed_password); if ($stmt->execute()) { return true; } } catch(PDOException $e) { return "Error: " . $e->getMessage(); } } // Login user public function login($email, $password) { try { $query = "SELECT * FROM " . $this->table . " WHERE email = :email"; $stmt = $this->db->prepare($query); $stmt->bindParam(':email', $email); $stmt->execute(); if ($stmt->rowCount() == 1) { $user = $stmt->fetch(); if (password_verify($password, $user['password'])) { $_SESSION['user_id'] = $user['id']; $_SESSION['user_name'] = $user['name']; $_SESSION['user_role'] = $user['role']; return true; } } return "Invalid email or password!"; } catch(PDOException $e) { return "Error: " . $e->getMessage(); } } // Get user by ID public function getUserById($id) { try { $query = "SELECT id, name, email, role, created_at FROM " . $this->table . " WHERE id = :id"; $stmt = $this->db->prepare($query); $stmt->bindParam(':id', $id); $stmt->execute(); return $stmt->fetch(); } catch(PDOException $e) { return null; } } } // Handle form submissions $user = new User(); $message = ''; if (isset($_POST['register'])) { $result = $user->register($_POST['name'], $_POST['email'], $_POST['password']); if ($result === true) { $message = "Registration successful! Please login."; } else { $message = $result; } } if (isset($_POST['login'])) { $result = $user->login($_POST['email'], $_POST['password']); if ($result === true) { header("Location: dashboard.php"); exit(); } else { $message = $result; } } ?> <!DOCTYPE html> <html> <head> <title>User Authentication</title> <style> body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; } .container { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; } .form-section { background: #f8f9fa; padding: 30px; border-radius: 10px; } .form-group { margin-bottom: 20px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 5px; box-sizing: border-box; } button { background: #007bff; color: white; padding: 12px 30px; border: none; border-radius: 5px; cursor: pointer; } button:hover { background: #0056b3; } .message { padding: 15px; margin-bottom: 20px; border-radius: 5px; } .success { background: #d4edda; color: #155724; } .error { background: #f8d7da; color: #721c24; } </style> </head> <body> <h1>User Authentication System</h1> <?php if ($message): ?> <div class="message <?= strpos($message, 'successful') !== false ? 'success' : 'error' ?>"> <?= $message ?> </div> <?php endif; ?> <div class="container"> <!-- Registration Form --> <div class="form-section"> <h2>Register</h2> <form method="POST"> <div class="form-group"> <label>Full Name</label> <input type="text" name="name" required> </div> <div class="form-group"> <label>Email</label> <input type="email" name="email" required> </div> <div class="form-group"> <label>Password</label> <input type="password" name="password" required minlength="6"> </div> <button type="submit" name="register">Register</button> </form> </div> <!-- Login Form --> <div class="form-section"> <h2>Login</h2> <form method="POST"> <div class="form-group"> <label>Email</label> <input type="email" name="email" required> </div> <div class="form-group"> <label>Password</label> <input type="password" name="password" required> </div> <button type="submit" name="login">Login</button> </form> </div> </div> </body> </html>
Part 2: File Uploads and Handling
2.1 Advanced File Upload System
<?php class FileManager { private $uploadDir = 'uploads/'; private $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt']; private $maxSize = 5 * 1024 * 1024; // 5MB public function __construct() { // Create upload directory if it doesn't exist if (!file_exists($this->uploadDir)) { mkdir($this->uploadDir, 0777, true); } } public function uploadFile($file) { $errors = []; $filePath = ''; if ($file['error'] === UPLOAD_ERR_OK) { $fileName = $file['name']; $fileTmp = $file['tmp_name']; $fileSize = $file['size']; $fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); // Generate unique filename $newFileName = uniqid() . '_' . time() . '.' . $fileExt; $filePath = $this->uploadDir . $newFileName; // Validate file type if (!in_array($fileExt, $this->allowedTypes)) { $errors[] = "File type not allowed. Allowed types: " . implode(', ', $this->allowedTypes); } // Validate file size if ($fileSize > $this->maxSize) { $errors[] = "File too large. Maximum size: " . ($this->maxSize / 1024 / 1024) . "MB"; } // Move file if no errors if (empty($errors)) { if (move_uploaded_file($fileTmp, $filePath)) { return [ 'success' => true, 'file_path' => $filePath, 'file_name' => $fileName, 'file_size' => $fileSize ]; } else { $errors[] = "Failed to upload file."; } } } else { $errors[] = "Upload error: " . $this->getUploadError($file['error']); } return [ 'success' => false, 'errors' => $errors ]; } public function getUploadedFiles() { $files = []; if (is_dir($this->uploadDir)) { $fileList = scandir($this->uploadDir); foreach ($fileList as $file) { if ($file !== '.' && $file !== '..') { $filePath = $this->uploadDir . $file; $files[] = [ 'name' => $file, 'path' => $filePath, 'size' => filesize($filePath), 'modified' => filemtime($filePath) ]; } } } return $files; } public function deleteFile($fileName) { $filePath = $this->uploadDir . $fileName; if (file_exists($filePath) && is_file($filePath)) { return unlink($filePath); } return false; } private function getUploadError($errorCode) { $errors = [ UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize directive', UPLOAD_ERR_FORM_SIZE => 'File exceeds MAX_FILE_SIZE directive', UPLOAD_ERR_PARTIAL => 'File was only partially uploaded', UPLOAD_ERR_NO_FILE => 'No file was uploaded', UPLOAD_ERR_NO_TMP_DIR => 'Missing temporary folder', UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk', UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload' ]; return $errors[$errorCode] ?? 'Unknown upload error'; } } // Handle file operations $fileManager = new FileManager(); $message = ''; if (isset($_POST['upload'])) { $result = $fileManager->uploadFile($_FILES['file']); if ($result['success']) { $message = "File uploaded successfully!"; } else { $message = "Upload failed: " . implode(', ', $result['errors']); } } if (isset($_GET['delete'])) { if ($fileManager->deleteFile($_GET['delete'])) { $message = "File deleted successfully!"; } else { $message = "Failed to delete file!"; } header("Location: " . str_replace('&delete=' . $_GET['delete'], '', $_SERVER['REQUEST_URI'])); exit(); } $uploadedFiles = $fileManager->getUploadedFiles(); ?> <!DOCTYPE html> <html> <head> <title>File Manager</title> <style> body { font-family: Arial, sans-serif; max-width: 1000px; margin: 0 auto; padding: 20px; } .container { display: grid; grid-template-columns: 1fr 2fr; gap: 30px; } .section { background: #f8f9fa; padding: 25px; border-radius: 10px; } .file-list { max-height: 500px; overflow-y: auto; } .file-item { background: white; padding: 15px; margin: 10px 0; border-radius: 5px; display: flex; justify-content: space-between; align-items: center; } .file-info { flex-grow: 1; } .file-actions a { margin-left: 10px; text-decoration: none; padding: 5px 10px; border-radius: 3px; } .delete-btn { background: #dc3545; color: white; } .view-btn { background: #007bff; color: white; } .message { padding: 15px; margin-bottom: 20px; border-radius: 5px; } .success { background: #d4edda; color: #155724; } .error { background: #f8d7da; color: #721c24; } </style> </head> <body> <h1>File Management System</h1> <?php if ($message): ?> <div class="message <?= strpos($message, 'successfully') !== false ? 'success' : 'error' ?>"> <?= $message ?> </div> <?php endif; ?> <div class="container"> <!-- Upload Section --> <div class="section"> <h2>Upload File</h2> <form method="POST" enctype="multipart/form-data"> <div style="margin-bottom: 20px;"> <input type="file" name="file" required style="padding: 10px;"> </div> <button type="submit" name="upload">Upload File</button> </form> <div style="margin-top: 20px; padding: 15px; background: #e9ecef; border-radius: 5px;"> <h3>Upload Guidelines:</h3> <ul> <li>Maximum file size: 5MB</li> <li>Allowed types: JPG, JPEG, PNG, GIF, PDF, TXT</li> <li>Files are renamed for security</li> </ul> </div> </div> <!-- File List Section --> <div class="section"> <h2>Uploaded Files (<?= count($uploadedFiles) ?>)</h2> <div class="file-list"> <?php if (empty($uploadedFiles)): ?> <p>No files uploaded yet.</p> <?php else: ?> <?php foreach($uploadedFiles as $file): ?> <div class="file-item"> <div class="file-info"> <strong><?= $file['name'] ?></strong><br> <small>Size: <?= round($file['size'] / 1024, 2) ?> KB</small><br> <small>Modified: <?= date('Y-m-d H:i', $file['modified']) ?></small> </div> <div class="file-actions"> <a href="<?= $file['path'] ?>" class="view-btn" target="_blank">View</a> <a href="?delete=<?= $file['name'] ?>" class="delete-btn" onclick="return confirm('Delete this file?')">Delete</a> </div> </div> <?php endforeach; ?> <?php endif; ?> </div> </div> </div> </body> </html>
Part 3: Object-Oriented PHP - Blog System
3.1 Complete Blog System with OOP
<?php session_start(); require_once 'Database.php'; class Post { private $db; private $table = 'posts'; public function __construct() { $database = new Database(); $this->db = $database->connect(); } // Create new post public function create($title, $content, $userId, $imagePath = null) { try { $query = "INSERT INTO " . $this->table . " (title, content, user_id, image_path) VALUES (:title, :content, :user_id, :image_path)"; $stmt = $this->db->prepare($query); $stmt->bindParam(':title', $title); $stmt->bindParam(':content', $content); $stmt->bindParam(':user_id', $userId); $stmt->bindParam(':image_path', $imagePath); return $stmt->execute(); } catch(PDOException $e) { return false; } } // Get all posts with user information public function getAll() { try { $query = "SELECT p.*, u.name as author_name FROM " . $this->table . " p LEFT JOIN users u ON p.user_id = u.id ORDER BY p.created_at DESC"; $stmt = $this->db->prepare($query); $stmt->execute(); return $stmt->fetchAll(); } catch(PDOException $e) { return []; } } // Get single post by ID public function getById($id) { try { $query = "SELECT p.*, u.name as author_name FROM " . $this->table . " p LEFT JOIN users u ON p.user_id = u.id WHERE p.id = :id"; $stmt = $this->db->prepare($query); $stmt->bindParam(':id', $id); $stmt->execute(); return $stmt->fetch(); } catch(PDOException $e) { return null; } } // Update post public function update($id, $title, $content, $imagePath = null) { try { $query = "UPDATE " . $this->table . " SET title = :title, content = :content, image_path = :image_path WHERE id = :id"; $stmt = $this->db->prepare($query); $stmt->bindParam(':id', $id); $stmt->bindParam(':title', $title); $stmt->bindParam(':content', $content); $stmt->bindParam(':image_path', $imagePath); return $stmt->execute(); } catch(PDOException $e) { return false; } } // Delete post public function delete($id) { try { $query = "DELETE FROM " . $this->table . " WHERE id = :id"; $stmt = $this->db->prepare($query); $stmt->bindParam(':id', $id); return $stmt->execute(); } catch(PDOException $e) { return false; } } } class BlogSystem { private $post; private $fileManager; public function __construct() { $this->post = new Post(); $this->fileManager = new FileManager(); } public function handleRequest() { $action = $_POST['action'] ?? $_GET['action'] ?? ''; $message = ''; switch ($action) { case 'create': if (isset($_SESSION['user_id'])) { $imagePath = null; // Handle file upload if (!empty($_FILES['image']['name'])) { $uploadResult = $this->fileManager->uploadFile($_FILES['image']); if ($uploadResult['success']) { $imagePath = $uploadResult['file_path']; } } if ($this->post->create($_POST['title'], $_POST['content'], $_SESSION['user_id'], $imagePath)) { $message = "Post created successfully!"; } else { $message = "Failed to create post!"; } } break; case 'delete': if (isset($_SESSION['user_id'])) { $post = $this->post->getById($_POST['post_id']); // Check if user owns the post or is admin if ($post && ($post['user_id'] == $_SESSION['user_id'] || $_SESSION['user_role'] == 'admin')) { if ($this->post->delete($_POST['post_id'])) { $message = "Post deleted successfully!"; } } } break; } return $message; } public function getAllPosts() { return $this->post->getAll(); } } // Initialize blog system $blogSystem = new BlogSystem(); $message = $blogSystem->handleRequest(); $posts = $blogSystem->getAllPosts(); ?> <!DOCTYPE html> <html> <head> <title>PHP Blog System</title> <style> body { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #f5f5f5; } .container { display: grid; grid-template-columns: 1fr 2fr; gap: 30px; } .section { background: white; padding: 25px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .post-form input, .post-form textarea { width: 100%; padding: 12px; margin: 8px 0; border: 1px solid #ddd; border-radius: 5px; box-sizing: border-box; } .post-form textarea { height: 150px; resize: vertical; } .post-item { background: white; padding: 20px; margin: 15px 0; border-radius: 8px; border-left: 4px solid #007bff; } .post-title { color: #333; margin: 0 0 10px 0; } .post-meta { color: #666; font-size: 0.9em; margin-bottom: 15px; } .post-content { line-height: 1.6; margin-bottom: 15px; } .post-image { max-width: 100%; height: auto; border-radius: 5px; margin: 10px 0; } .btn { padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; text-decoration: none; display: inline-block; } .btn-primary { background: #007bff; color: white; } .btn-danger { background: #dc3545; color: white; } .message { padding: 15px; margin-bottom: 20px; border-radius: 5px; } .success { background: #d4edda; color: #155724; } .error { background: #f8d7da; color: #721c24; } </style> </head> <body> <h1>PHP Blog System</h1> <?php if ($message): ?> <div class="message <?= strpos($message, 'successfully') !== false ? 'success' : 'error' ?>"> <?= $message ?> </div> <?php endif; ?> <div class="container"> <!-- Create Post Form --> <?php if (isset($_SESSION['user_id'])): ?> <div class="section"> <h2>Create New Post</h2> <form method="POST" enctype="multipart/form-data" class="post-form"> <input type="hidden" name="action" value="create"> <div> <label>Post Title</label> <input type="text" name="title" required> </div> <div> <label>Content</label> <textarea name="content" required></textarea> </div> <div> <label>Featured Image (Optional)</label> <input type="file" name="image" accept="image/*"> </div> <button type="submit" class="btn btn-primary">Publish Post</button> </form> </div> <?php else: ?> <div class="section"> <h2>Welcome to Our Blog</h2> <p>Please <a href="auth.php">login</a> to create posts.</p> </div> <?php endif; ?> <!-- Blog Posts --> <div class="section"> <h2>Latest Posts</h2> <?php if (empty($posts)): ?> <p>No posts yet. Be the first to post!</p> <?php else: ?> <?php foreach($posts as $post): ?> <div class="post-item"> <h3 class="post-title"><?= htmlspecialchars($post['title']) ?></h3> <div class="post-meta"> By <?= htmlspecialchars($post['author_name']) ?> | <?= date('F j, Y g:i A', strtotime($post['created_at'])) ?> <?php if ($post['updated_at'] != $post['created_at']): ?> | Updated: <?= date('F j, Y g:i A', strtotime($post['updated_at'])) ?> <?php endif; ?> </div> <?php if ($post['image_path']): ?> <img src="<?= $post['image_path'] ?>" alt="Post image" class="post-image"> <?php endif; ?> <div class="post-content"> <?= nl2br(htmlspecialchars($post['content'])) ?> </div> <?php if (isset($_SESSION['user_id']) && ($_SESSION['user_id'] == $post['user_id'] || $_SESSION['user_role'] == 'admin')): ?> <form method="POST" style="display: inline;"> <input type="hidden" name="action" value="delete"> <input type="hidden" name="post_id" value="<?= $post['id'] ?>"> <button type="submit" class="btn btn-danger" onclick="return confirm('Delete this post?')">Delete</button> </form> <?php endif; ?> </div> <?php endforeach; ?> <?php endif; ?> </div> </div> </body> </html>
Part 4: Dashboard for Logged-in Users
4.1 User Dashboard
<?php // dashboard.php session_start(); require_once 'Database.php'; if (!isset($_SESSION['user_id'])) { header("Location: auth.php"); exit(); } $user = new User(); $currentUser = $user->getUserById($_SESSION['user_id']); ?> <!DOCTYPE html> <html> <head> <title>Dashboard</title> <style> body { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; } .header { background: #007bff; color: white; padding: 20px; border-radius: 10px; margin-bottom: 30px; } .nav { background: #f8f9fa; padding: 15px; border-radius: 5px; margin-bottom: 20px; } .nav a { margin-right: 15px; text-decoration: none; color: #007bff; } .stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-bottom: 30px; } .stat-card { background: white; padding: 20px; border-radius: 8px; text-align: center; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } </style> </head> <body> <div class="header"> <h1>Welcome, <?= $currentUser['name'] ?>!</h1> <p>Role: <?= ucfirst($currentUser['role']) ?> | Member since: <?= date('F Y', strtotime($currentUser['created_at'])) ?></p> </div> <div class="nav"> <a href="blog.php">Blog</a> <a href="file_manager.php">File Manager</a> <a href="logout.php">Logout</a> </div> <div class="stats"> <div class="stat-card"> <h3>Blog Posts</h3> <p>12</p> </div> <div class="stat-card"> <h3>Files Uploaded</h3> <p>8</p> </div> <div class="stat-card"> <h3>Comments</h3> <p>23</p> </div> </div> <h2>Quick Actions</h2> <div class="stats"> <div class="stat-card"> <h4>Write New Post</h4> <a href="blog.php" class="btn btn-primary">Create Post</a> </div> <div class="stat-card"> <h4>Upload Files</h4> <a href="file_manager.php" class="btn btn-primary">Upload</a> </div> <div class="stat-card"> <h4>Manage Profile</h4> <a href="profile.php" class="btn btn-primary">Profile</a> </div> </div> </body> </html>
Key Concepts Covered:
-
Database Integration: PDO, prepared statements, relationships
-
File Handling: Upload, validation, management
-
Object-Oriented Programming: Classes, methods, encapsulation
-
Session Management: User authentication and authorization
-
Security: SQL injection prevention, file type validation
-
Error Handling: Try-catch blocks, user-friendly messages
Practice Exercises:
-
Add a comment system to the blog
-
Implement user profile editing
-
Create an admin panel for user management
-
Add pagination to the blog posts
-
Implement image resizing for uploaded images
Next Lesson Preview:
In Lesson 4, we'll cover:
-
RESTful APIs with PHP
-
AJAX integration
-
Email sending
-
Payment gateway integration
-
Building a complete e-commerce system
You've now built a complete web application with database integration, file handling, and object-oriented programming! These are the skills used in real-world PHP development.
Tags:
What's Your Reaction?