1. php
  2. /web development

PHP Web Development

Introduction to PHP Web Development

PHP was specifically designed for web development, making it one of the most popular server-side scripting languages for building dynamic websites and web applications. PHP powers over 75% of websites whose server-side language is known, including major platforms like WordPress, Facebook, and Wikipedia.

This guide covers the essential concepts and techniques for building modern web applications with PHP.

How PHP Works in Web Development

PHP is a server-side language that executes on the web server before sending the final HTML to the user's browser:

<!DOCTYPE html>
<html>
<head>
    <title><?php echo "Dynamic Page Title"; ?></title>
</head>
<body>
    <h1>Welcome to Our Site</h1>
    <p>Today's date is: <?php echo date('Y-m-d H:i:s'); ?></p>
    <p>Your IP address is: <?php echo $_SERVER['REMOTE_ADDR']; ?></p>
    
    <?php
    $visitors = rand(100, 1000);
    echo "<p>Current visitors online: $visitors</p>";
    ?>
</body>
</html>

Working with Forms

Forms are the primary way to collect user input on websites. PHP makes form handling straightforward:

Basic Form Processing

<!-- contact.html -->
<form action="process_contact.php" method="POST">
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>
    
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
    
    <label for="message">Message:</label>
    <textarea id="message" name="message" required></textarea>
    
    <button type="submit">Send Message</button>
</form>
<?php
// process_contact.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = htmlspecialchars($_POST['name']);
    $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
    $message = htmlspecialchars($_POST['message']);
    
    // Validate input
    if (empty($name) || empty($email) || empty($message)) {
        $error = "All fields are required.";
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $error = "Invalid email address.";
    } else {
        // Process the form (save to database, send email, etc.)
        $success = "Thank you for your message, $name!";
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Contact Form Result</title>
</head>
<body>
    <?php if (isset($error)): ?>
        <div class="error"><?php echo $error; ?></div>
    <?php elseif (isset($success)): ?>
        <div class="success"><?php echo $success; ?></div>
    <?php endif; ?>
    
    <a href="contact.html">Back to Contact Form</a>
</body>
</html>

Advanced Form Handling

<?php
class FormHandler {
    private $data = [];
    private $errors = [];
    
    public function __construct($postData) {
        $this->data = $postData;
    }
    
    public function validate() {
        $this->validateRequired(['name', 'email', 'message']);
        $this->validateEmail('email');
        $this->validateLength('message', 10, 500);
        
        return empty($this->errors);
    }
    
    private function validateRequired($fields) {
        foreach ($fields as $field) {
            if (empty($this->data[$field])) {
                $this->errors[$field] = ucfirst($field) . " is required.";
            }
        }
    }
    
    private function validateEmail($field) {
        if (!empty($this->data[$field]) && !filter_var($this->data[$field], FILTER_VALIDATE_EMAIL)) {
            $this->errors[$field] = "Invalid email address.";
        }
    }
    
    private function validateLength($field, $min, $max) {
        $length = strlen($this->data[$field]);
        if (!empty($this->data[$field]) && ($length < $min || $length > $max)) {
            $this->errors[$field] = ucfirst($field) . " must be between $min and $max characters.";
        }
    }
    
    public function getErrors() {
        return $this->errors;
    }
    
    public function getData($field) {
        return htmlspecialchars($this->data[$field] ?? '');
    }
}

// Usage
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $form = new FormHandler($_POST);
    
    if ($form->validate()) {
        // Process form data
        $success = "Form submitted successfully!";
    } else {
        $errors = $form->getErrors();
    }
}
?>

Sessions and User Management

Sessions allow you to store user data across multiple page requests:

Basic Session Management

<?php
// Start session at the beginning of each page
session_start();

// Login processing
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];
    
    // Verify credentials (simplified example)
    if ($username === 'admin' && $password === 'password') {
        $_SESSION['user_id'] = 1;
        $_SESSION['username'] = $username;
        $_SESSION['logged_in'] = true;
        
        header('Location: dashboard.php');
        exit;
    } else {
        $error = "Invalid credentials";
    }
}

// Logout processing
if (isset($_GET['logout'])) {
    session_destroy();
    header('Location: login.php');
    exit;
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <?php if (isset($error)): ?>
        <div class="error"><?php echo $error; ?></div>
    <?php endif; ?>
    
    <?php if (isset($_SESSION['logged_in'])): ?>
        <h1>Welcome, <?php echo $_SESSION['username']; ?>!</h1>
        <a href="?logout=1">Logout</a>
    <?php else: ?>
        <form method="POST">
            <input type="text" name="username" placeholder="Username" required>
            <input type="password" name="password" placeholder="Password" required>
            <button type="submit" name="login">Login</button>
        </form>
    <?php endif; ?>
</body>
</html>

Advanced Session Management Class

<?php
class SessionManager {
    private static $instance = null;
    
    private function __construct() {
        $this->startSession();
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function startSession() {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
    }
    
    public function set($key, $value) {
        $_SESSION[$key] = $value;
    }
    
    public function get($key, $default = null) {
        return $_SESSION[$key] ?? $default;
    }
    
    public function remove($key) {
        unset($_SESSION[$key]);
    }
    
    public function destroy() {
        session_destroy();
    }
    
    public function isLoggedIn() {
        return $this->get('logged_in', false);
    }
    
    public function login($userId, $username) {
        $this->set('user_id', $userId);
        $this->set('username', $username);
        $this->set('logged_in', true);
        $this->set('login_time', time());
    }
    
    public function logout() {
        $this->destroy();
    }
    
    public function requireLogin() {
        if (!$this->isLoggedIn()) {
            header('Location: login.php');
            exit;
        }
    }
}

// Usage
$session = SessionManager::getInstance();
$session->requireLogin(); // Protect a page
?>

Working with Cookies

Cookies store small amounts of data in the user's browser:

<?php
// Setting cookies
function setUserPreferences($theme, $language) {
    // Cookies expire in 30 days
    $expiry = time() + (30 * 24 * 60 * 60);
    
    setcookie('user_theme', $theme, $expiry, '/');
    setcookie('user_language', $language, $expiry, '/');
}

// Reading cookies
function getUserPreferences() {
    return [
        'theme' => $_COOKIE['user_theme'] ?? 'light',
        'language' => $_COOKIE['user_language'] ?? 'en'
    ];
}

// Process preference changes
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $theme = $_POST['theme'];
    $language = $_POST['language'];
    
    setUserPreferences($theme, $language);
    $message = "Preferences saved!";
}

$prefs = getUserPreferences();
?>

<!DOCTYPE html>
<html>
<head>
    <title>User Preferences</title>
    <link rel="stylesheet" href="themes/<?php echo $prefs['theme']; ?>.css">
</head>
<body>
    <h1>User Preferences</h1>
    
    <?php if (isset($message)): ?>
        <div class="success"><?php echo $message; ?></div>
    <?php endif; ?>
    
    <form method="POST">
        <label>Theme:</label>
        <select name="theme">
            <option value="light" <?php echo $prefs['theme'] === 'light' ? 'selected' : ''; ?>>Light</option>
            <option value="dark" <?php echo $prefs['theme'] === 'dark' ? 'selected' : ''; ?>>Dark</option>
        </select>
        
        <label>Language:</label>
        <select name="language">
            <option value="en" <?php echo $prefs['language'] === 'en' ? 'selected' : ''; ?>>English</option>
            <option value="es" <?php echo $prefs['language'] === 'es' ? 'selected' : ''; ?>>Spanish</option>
            <option value="fr" <?php echo $prefs['language'] === 'fr' ? 'selected' : ''; ?>>French</option>
        </select>
        
        <button type="submit">Save Preferences</button>
    </form>
</body>
</html>

File Uploads

Handling file uploads securely is crucial for web applications:

<?php
class FileUploadHandler {
    private $uploadDir;
    private $allowedTypes;
    private $maxSize;
    
    public function __construct($uploadDir = 'uploads/', $maxSize = 5242880) { // 5MB default
        $this->uploadDir = $uploadDir;
        $this->maxSize = $maxSize;
        $this->allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'];
        
        // Create upload directory if it doesn't exist
        if (!is_dir($this->uploadDir)) {
            mkdir($this->uploadDir, 0755, true);
        }
    }
    
    public function handleUpload($fileInput) {
        if (!isset($_FILES[$fileInput])) {
            return ['success' => false, 'message' => 'No file uploaded'];
        }
        
        $file = $_FILES[$fileInput];
        
        // Check for upload errors
        if ($file['error'] !== UPLOAD_ERR_OK) {
            return ['success' => false, 'message' => 'Upload error: ' . $file['error']];
        }
        
        // Validate file size
        if ($file['size'] > $this->maxSize) {
            return ['success' => false, 'message' => 'File too large'];
        }
        
        // Validate file type
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, $this->allowedTypes)) {
            return ['success' => false, 'message' => 'File type not allowed'];
        }
        
        // Generate unique filename
        $filename = uniqid() . '.' . $extension;
        $destination = $this->uploadDir . $filename;
        
        // Move uploaded file
        if (move_uploaded_file($file['tmp_name'], $destination)) {
            return [
                'success' => true,
                'message' => 'File uploaded successfully',
                'filename' => $filename,
                'path' => $destination
            ];
        } else {
            return ['success' => false, 'message' => 'Failed to move uploaded file'];
        }
    }
}

// Usage
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload'])) {
    $uploader = new FileUploadHandler();
    $result = $uploader->handleUpload('upload');
    
    if ($result['success']) {
        $success = $result['message'];
        $uploadedFile = $result['filename'];
    } else {
        $error = $result['message'];
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>File Upload</title>
</head>
<body>
    <h1>File Upload</h1>
    
    <?php if (isset($error)): ?>
        <div class="error"><?php echo $error; ?></div>
    <?php endif; ?>
    
    <?php if (isset($success)): ?>
        <div class="success"><?php echo $success; ?></div>
        <p>Uploaded file: <?php echo $uploadedFile; ?></p>
    <?php endif; ?>
    
    <form method="POST" enctype="multipart/form-data">
        <label for="upload">Choose file:</label>
        <input type="file" id="upload" name="upload" required>
        <button type="submit">Upload</button>
    </form>
</body>
</html>

URL Routing and Pretty URLs

Create clean, SEO-friendly URLs:

<?php
class Router {
    private $routes = [];
    
    public function addRoute($pattern, $callback) {
        $this->routes[$pattern] = $callback;
    }
    
    public function dispatch($uri) {
        foreach ($this->routes as $pattern => $callback) {
            if (preg_match($pattern, $uri, $matches)) {
                array_shift($matches); // Remove full match
                return call_user_func_array($callback, $matches);
            }
        }
        
        // 404 Not Found
        http_response_code(404);
        echo "Page not found";
    }
}

// Create router instance
$router = new Router();

// Define routes
$router->addRoute('/^$/', function() {
    include 'pages/home.php';
});

$router->addRoute('/^about$/', function() {
    include 'pages/about.php';
});

$router->addRoute('/^user\/(\d+)$/', function($userId) {
    include 'pages/user.php';
    // $userId is available in user.php
});

$router->addRoute('/^blog\/([a-z0-9-]+)$/', function($slug) {
    include 'pages/blog-post.php';
    // $slug is available in blog-post.php
});

// Get the current URI
$uri = trim($_SERVER['REQUEST_URI'], '/');

// Remove query string
$uri = strtok($uri, '?');

// Dispatch the request
$router->dispatch($uri);
?>

AJAX and JSON Responses

Handle AJAX requests and return JSON data:

<?php
// api.php - Simple API endpoint
header('Content-Type: application/json');

function sendJsonResponse($data, $statusCode = 200) {
    http_response_code($statusCode);
    echo json_encode($data);
    exit;
}

$action = $_GET['action'] ?? '';

switch ($action) {
    case 'get_users':
        $users = [
            ['id' => 1, 'name' => 'John Doe', 'email' => '[email protected]'],
            ['id' => 2, 'name' => 'Jane Smith', 'email' => '[email protected]']
        ];
        sendJsonResponse(['success' => true, 'data' => $users]);
        break;
        
    case 'create_user':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            sendJsonResponse(['success' => false, 'message' => 'POST method required'], 405);
        }
        
        $input = json_decode(file_get_contents('php://input'), true);
        
        if (empty($input['name']) || empty($input['email'])) {
            sendJsonResponse(['success' => false, 'message' => 'Name and email required'], 400);
        }
        
        // Simulate user creation
        $newUser = [
            'id' => rand(1000, 9999),
            'name' => $input['name'],
            'email' => $input['email']
        ];
        
        sendJsonResponse(['success' => true, 'data' => $newUser]);
        break;
        
    default:
        sendJsonResponse(['success' => false, 'message' => 'Invalid action'], 400);
}
?>
<!-- Frontend JavaScript -->
<script>
async function fetchUsers() {
    try {
        const response = await fetch('api.php?action=get_users');
        const data = await response.json();
        
        if (data.success) {
            displayUsers(data.data);
        } else {
            console.error('Error:', data.message);
        }
    } catch (error) {
        console.error('Network error:', error);
    }
}

async function createUser(name, email) {
    try {
        const response = await fetch('api.php?action=create_user', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ name, email })
        });
        
        const data = await response.json();
        
        if (data.success) {
            console.log('User created:', data.data);
            fetchUsers(); // Refresh the list
        } else {
            console.error('Error:', data.message);
        }
    } catch (error) {
        console.error('Network error:', error);
    }
}

function displayUsers(users) {
    const container = document.getElementById('users');
    container.innerHTML = users.map(user => 
        `<div class="user">
            <h3>${user.name}</h3>
            <p>${user.email}</p>
        </div>`
    ).join('');
}

// Load users when page loads
document.addEventListener('DOMContentLoaded', fetchUsers);
</script>

Security Best Practices

Input Validation and Sanitization

<?php
class SecurityHelper {
    public static function sanitizeInput($input, $type = 'string') {
        switch ($type) {
            case 'email':
                return filter_var($input, FILTER_SANITIZE_EMAIL);
            case 'url':
                return filter_var($input, FILTER_SANITIZE_URL);
            case 'int':
                return filter_var($input, FILTER_SANITIZE_NUMBER_INT);
            case 'float':
                return filter_var($input, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
            default:
                return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
        }
    }
    
    public static function validateInput($input, $type = 'string', $options = []) {
        switch ($type) {
            case 'email':
                return filter_var($input, FILTER_VALIDATE_EMAIL);
            case 'url':
                return filter_var($input, FILTER_VALIDATE_URL);
            case 'int':
                return filter_var($input, FILTER_VALIDATE_INT, $options);
            case 'float':
                return filter_var($input, FILTER_VALIDATE_FLOAT, $options);
            case 'required':
                return !empty(trim($input));
            default:
                return is_string($input);
        }
    }
    
    public static function generateCSRFToken() {
        if (!isset($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }
    
    public static function validateCSRFToken($token) {
        return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
    }
}
?>

Explore these related PHP web development topics:

Summary

PHP web development encompasses a wide range of topics from basic form handling to complex application architecture. Key concepts include:

  • Form Processing: Safely handling user input with validation and sanitization
  • Session Management: Maintaining user state across requests
  • File Uploads: Securely handling file uploads with proper validation
  • URL Routing: Creating clean, SEO-friendly URLs
  • AJAX Integration: Building interactive user interfaces
  • Security: Implementing proper security measures to protect your application

Modern PHP web development often involves using frameworks like Laravel, Symfony, or CodeIgniter, but understanding these fundamental concepts is essential for building secure, maintainable web applications regardless of the tools you choose.