Embedding PHP in HTML

Creating dynamic web pages with PHP and HTML integration

Introduction to PHP and HTML Integration

One of PHP's most powerful features is its ability to seamlessly integrate with HTML. Unlike purely backend languages that require a separate templating system, PHP was designed from the beginning to be embedded directly within HTML markup.

Think of PHP as the dynamic chef in a restaurant kitchen who prepares specific dishes (dynamic content) while HTML provides the fixed menu and dining room layout (static structure). Together, they create a complete dining experience (web page) for the customer (user).

This integration allows developers to:

PHP Tags and Syntax in HTML

To embed PHP code within an HTML file, we use special PHP tags. The web server processes everything between these tags as PHP code, while everything outside is sent directly to the browser as HTML.

Standard PHP Tags


<!DOCTYPE html>
<html>
<head>
    <title>My PHP Page</title>
</head>
<body>
    <h1>Welcome to My Website</h1>
    
    <p>The current date and time is: 
        <?php 
            echo date("Y-m-d H:i:s"); 
        ?>
    </p>
    
    <p>This is regular HTML content.</p>
</body>
</html>
            

Short Echo Tag

PHP provides a short echo tag (<?=) specifically for outputting variables or expressions directly in HTML:


<p>Hello, <?= $username ?>!</p>

<!-- This is equivalent to: -->
<p>Hello, <?php echo $username; ?>!</p>
            

The short echo tag is perfect for embedding simple variables or expressions without the verbosity of a full PHP tag with echo.

PHP Code Blocks

You can include multiple PHP statements within a single PHP block:


<div class="user-profile">
    <?php
        // Multiple PHP statements in one block
        $user = getUserById(123);
        $formattedDate = date("F j, Y", strtotime($user['joined_date']));
        $postCount = countUserPosts($user['id']);
    ?>
    
    <h2>Profile: <?= $user['username'] ?></h2>
    <p>Joined: <?= $formattedDate ?></p>
    <p>Posts: <?= $postCount ?></p>
</div>
            

Notice how we process multiple PHP statements in one block, then use the short echo tag to output the results in various places in the HTML.

Switching Between PHP and HTML

You can alternate between PHP and HTML as many times as needed in a file:


<?php
    $isLoggedIn = checkUserLogin();
    $themeColor = getUserTheme();
?>

<!DOCTYPE html>
<html>
<head>
    <title>My Website</title>
    <style>
        body {
            background-color: <?= $themeColor ?>;
        }
    </style>
</head>
<body>
    <?php if ($isLoggedIn): ?>
        <h1>Welcome back, <?= $username ?>!</h1>
        <a href="logout.php">Logout</a>
    <?php else: ?>
        <h1>Welcome, Guest!</h1>
        <a href="login.php">Login</a>
    <?php endif; ?>
</body>
</html>
            

This example demonstrates:

Outputting Dynamic Content

One of the primary uses of embedding PHP in HTML is to output dynamic content. Let's explore various techniques for doing this effectively.

Basic Variable Output


<!-- User profile information -->
<div class="profile-card">
    <h2><?= $user['name'] ?></h2>
    <p><?= $user['email'] ?></p>
    <p>Member since: <?= date("M Y", strtotime($user['joined_date'])) ?></p>
</div>
            

Escaping Output for Security

When outputting user-provided content, always escape it to prevent cross-site scripting (XSS) attacks:


<!-- Unsafe (vulnerable to XSS attacks) -->
<div class="comment">
    <h3><?= $comment['author'] ?> said:</h3>
    <p><?= $comment['text'] ?></p>
</div>

<!-- Safe (escaped content) -->
<div class="comment">
    <h3><?= htmlspecialchars($comment['author']) ?> said:</h3>
    <p><?= htmlspecialchars($comment['text']) ?></p>
</div>
            

The htmlspecialchars() function converts special characters to their HTML entities, preventing them from being interpreted as code. This is essential for security when displaying user-submitted content.

Formatting Output

PHP provides many functions for formatting data before output:


<!-- Price formatting -->
<p class="price">$<?= number_format($product['price'], 2) ?></p>

<!-- Date formatting -->
<p class="published">Published: <?= date("F j, Y", strtotime($article['publish_date'])) ?></p>

<!-- Text truncation -->
<p class="excerpt"><?= substr($article['content'], 0, 150) ?>...</p>

<!-- String transformation -->
<h1 class="title"><?= strtoupper($page['title']) ?></h1>
            

Conditional HTML with PHP

One of the most powerful features of embedding PHP in HTML is the ability to conditionally render different HTML content based on PHP logic.

Basic Conditional Rendering


<!-- Display a message only if it exists -->
<?php if (isset($message)): ?>
    <div class="alert"><?= $message ?></div>
<?php endif; ?>

<!-- Show different content for logged-in users vs. guests -->
<?php if ($isLoggedIn): ?>
    <div class="dashboard">
        <h2>Welcome back, <?= $username ?></h2>
        <a href="dashboard.php">View Dashboard</a>
        <a href="logout.php">Logout</a>
    </div>
<?php else: ?>
    <div class="login-prompt">
        <h2>Welcome, Guest</h2>
        <p>Please <a href="login.php">login</a> or <a href="register.php">register</a> to access your dashboard.</p>
    </div>
<?php endif; ?>
            

Notice the use of the alternative syntax (if():...endif;) which is more readable in HTML templates than the standard curly brace syntax.

Multiple Conditions


<!-- Display different user status badges -->
<div class="user-card">
    <h3><?= $user['name'] ?></h3>
    
    <?php if ($user['role'] === 'admin'): ?>
        <span class="badge admin">Administrator</span>
    <?php elseif ($user['role'] === 'moderator'): ?>
        <span class="badge moderator">Moderator</span>
    <?php elseif ($user['premium_member']): ?>
        <span class="badge premium">Premium Member</span>
    <?php else: ?>
        <span class="badge member">Member</span>
    <?php endif; ?>
</div>
            

Conditional CSS Classes

You can use PHP to conditionally add CSS classes to elements:


<!-- Add a class based on a condition -->
<div class="product <?= ($product['in_stock'] ? '' : 'out-of-stock') ?>">
    <h3><?= $product['name'] ?></h3>
    <p>$<?= number_format($product['price'], 2) ?></p>
</div>

<!-- Multiple conditional classes -->
<div class="alert <?= $message['type'] ?> <?= $message['dismissible'] ? 'dismissible' : '' ?>">
    <?= $message['text'] ?>
</div>
            

This technique allows you to create dynamic UI components that change their appearance based on data.

Nested Conditions


<div class="order-summary">
    <?php if ($order['status'] === 'completed'): ?>
        <div class="status completed">Order Completed</div>
        
        <?php if ($order['feedback'] === null): ?>
            <div class="feedback-request">
                <p>How was your experience? Please leave feedback.</p>
                <a href="feedback.php?order=<?= $order['id'] ?>" class="button">Leave Feedback</a>
            </div>
        <?php endif; ?>
        
    <?php elseif ($order['status'] === 'shipped'): ?>
        <div class="status shipped">Order Shipped</div>
        <p>Your order was shipped on <?= date("M j, Y", strtotime($order['ship_date'])) ?>.</p>
        
        <?php if ($order['tracking_number']): ?>
            <p>Tracking number: <?= $order['tracking_number'] ?></p>
            <a href="track.php?number=<?= $order['tracking_number'] ?>" class="button">Track Package</a>
        <?php endif; ?>
        
    <?php else: ?>
        <div class="status <?= $order['status'] ?>">Order <?= ucfirst($order['status']) ?></div>
    <?php endif; ?>
</div>
            

This example demonstrates nested conditional rendering for a complex order status display, with different content shown based on multiple conditions.

Loops in HTML Templates

Another powerful feature of PHP is the ability to generate repetitive HTML structures using loops.

Basic Looping with foreach


<!-- Product listing -->
<div class="product-grid">
    <?php foreach ($products as $product): ?>
        <div class="product-card">
            <h3><?= htmlspecialchars($product['name']) ?></h3>
            <p class="price">$<?= number_format($product['price'], 2) ?></p>
            <p class="description"><?= htmlspecialchars($product['description']) ?></p>
            <button class="add-to-cart" data-id="<?= $product['id'] ?>">Add to Cart</button>
        </div>
    <?php endforeach; ?>
</div>
            

This is one of the most common patterns in PHP web development - using a foreach loop to iterate through an array of data and generate HTML for each item.

Nested Loops


<!-- Category and product listing -->
<div class="catalog">
    <?php foreach ($categories as $category): ?>
        <div class="category">
            <h2><?= htmlspecialchars($category['name']) ?></h2>
            
            <div class="product-list">
                <?php if (count($category['products']) > 0): ?>
                    <?php foreach ($category['products'] as $product): ?>
                        <div class="product-item">
                            <h3><?= htmlspecialchars($product['name']) ?></h3>
                            <p>$<?= number_format($product['price'], 2) ?></p>
                        </div>
                    <?php endforeach; ?>
                <?php else: ?>
                    <p class="empty-category">No products in this category.</p>
                <?php endif; ?>
            </div>
        </div>
    <?php endforeach; ?>
</div>
            

Here we combine nested loops with conditional rendering to create a hierarchical display of categories and their products.

Loop with Counter


<!-- Numbered list with alternating row colors -->
<ol class="ranked-list">
    <?php $counter = 0; ?>
    <?php foreach ($items as $item): ?>
        <?php $counter++; ?>
        <li class="<?= $counter % 2 === 0 ? 'even' : 'odd' ?>">
            <?= htmlspecialchars($item['name']) ?>
            <?php if ($counter <= 3): ?>
                <span class="top-rank">Top <?= $counter ?>!</span>
            <?php endif; ?>
        </li>
    <?php endforeach; ?>
</ol>
            

This example shows how to maintain a counter variable while looping, which can be useful for numbered lists, pagination, or creating alternating row styles.

Building Tables with Loops


<!-- Data table -->
<table class="data-table">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Date Joined</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        <?php if (count($users) > 0): ?>
            <?php foreach ($users as $user): ?>
                <tr>
                    <td><?= $user['id'] ?></td>
                    <td><?= htmlspecialchars($user['name']) ?></td>
                    <td><?= htmlspecialchars($user['email']) ?></td>
                    <td><?= date("Y-m-d", strtotime($user['date_joined'])) ?></td>
                    <td>
                        <a href="edit.php?id=<?= $user['id'] ?>" class="btn btn-edit">Edit</a>
                        <a href="delete.php?id=<?= $user['id'] ?>" class="btn btn-delete">Delete</a>
                    </td>
                </tr>
            <?php endforeach; ?>
        <?php else: ?>
            <tr>
                <td colspan="5" class="no-data">No users found.</td>
            </tr>
        <?php endif; ?>
    </tbody>
</table>
            

Tables are a common use case for PHP loops, especially in admin panels and data management interfaces.

flowchart TD A[PHP Array] --> B[foreach Loop] B --> C[HTML Template] C --> D[Generated HTML for each item] D --> E[Complete HTML Page]

Including Reusable Components

PHP's include and require statements allow you to break your HTML into reusable components, similar to modern front-end frameworks but server-rendered.

Basic File Inclusion


<!-- index.php -->
<!DOCTYPE html>
<html>
<head>
    <title>My Website - <?= $pageTitle ?></title>
    <?php include 'includes/head-meta.php'; ?>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <?php include 'includes/header.php'; ?>
    
    <main>
        <h1><?= $pageTitle ?></h1>
        <?php include 'includes/content-' . $pageSlug . '.php'; ?>
    </main>
    
    <?php include 'includes/footer.php'; ?>
</body>
</html>
            

This example demonstrates how to use include to include common elements like headers and footers, as well as dynamic content based on variables.

Component with Parameters


<!-- Using a reusable card component -->
<div class="products">
    <?php foreach ($products as $product): ?>
        <?php
            // Set up parameters for the component
            $componentData = [
                'title' => $product['name'],
                'image' => $product['image_url'],
                'price' => $product['price'],
                'description' => $product['description'],
                'button_text' => 'Add to Cart',
                'button_action' => 'cart.php?add=' . $product['id']
            ];
        ?>
        <?php include 'components/product-card.php'; ?>
    <?php endforeach; ?>
</div>

<!-- components/product-card.php -->
<div class="product-card">
    <img src="<?= htmlspecialchars($componentData['image']) ?>" alt="<?= htmlspecialchars($componentData['title']) ?>">
    <h3><?= htmlspecialchars($componentData['title']) ?></h3>
    <p class="price">$<?= number_format($componentData['price'], 2) ?></p>
    <p class="description"><?= htmlspecialchars($componentData['description']) ?></p>
    <a href="<?= $componentData['button_action'] ?>" class="button"><?= htmlspecialchars($componentData['button_text']) ?></a>
</div>
            

This example demonstrates how to create a reusable component that accepts parameters, similar to how components work in modern frontend frameworks.

Layout Templates


<!-- Defining a layout system -->

<!-- layout.php -->
<!DOCTYPE html>
<html>
<head>
    <title><?= $pageTitle ?? 'My Website' ?></title>
    <link rel="stylesheet" href="css/styles.css">
    <?php if (isset($extraStyles)): ?>
        <link rel="stylesheet" href="<?= $extraStyles ?>">
    <?php endif; ?>
</head>
<body class="<?= $bodyClass ?? '' ?>">
    <?php include 'includes/header.php'; ?>
    
    <main>
        <?php include $contentFile; ?>
    </main>
    
    <?php include 'includes/footer.php'; ?>
    
    <?php if (isset($extraScripts)): ?>
        <script src="<?= $extraScripts ?>"></script>
    <?php endif; ?>
</body>
</html>

<!-- Using the layout in a page -->
<?php
// about.php
$pageTitle = 'About Us';
$bodyClass = 'about-page';
$contentFile = 'content/about-content.php';
$extraStyles = 'css/about.css';
$extraScripts = 'js/about.js';

include 'layout.php';
?>
            

This approach creates a flexible layout system where each page specifies its content and requirements, while the layout template handles the common structure.

Form Handling with PHP

One of the most common uses of embedding PHP in HTML is to create and process forms. PHP can both generate form elements dynamically and handle form submissions.

Basic Form Processing


<!-- contact.php -->
<?php
$errors = [];
$success = false;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Validate form inputs
    if (empty($_POST['name'])) {
        $errors['name'] = 'Name is required';
    }
    
    if (empty($_POST['email'])) {
        $errors['email'] = 'Email is required';
    } elseif (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
        $errors['email'] = 'Valid email is required';
    }
    
    if (empty($_POST['message'])) {
        $errors['message'] = 'Message is required';
    }
    
    // If no errors, process the form
    if (empty($errors)) {
        // In a real app, you would send an email, save to database, etc.
        $success = true;
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Contact Us</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <h1>Contact Us</h1>
    
    <?php if ($success): ?>
        <div class="success-message">
            <h2>Thank you for your message!</h2>
            <p>We will get back to you as soon as possible.</p>
            <a href="index.php">Return to Home</a>
        </div>
    <?php else: ?>
        <form method="post" action="">
            <div class="form-group">
                <label for="name">Name:</label>
                <input type="text" id="name" name="name" value="<?= htmlspecialchars($_POST['name'] ?? '') ?>">
                <?php if (isset($errors['name'])): ?>
                    <span class="error"><?= $errors['name'] ?></span>
                <?php endif; ?>
            </div>
            
            <div class="form-group">
                <label for="email">Email:</label>
                <input type="email" id="email" name="email" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>">
                <?php if (isset($errors['email'])): ?>
                    <span class="error"><?= $errors['email'] ?></span>
                <?php endif; ?>
            </div>
            
            <div class="form-group">
                <label for="message">Message:</label>
                <textarea id="message" name="message" rows="5"><?= htmlspecialchars($_POST['message'] ?? '') ?></textarea>
                <?php if (isset($errors['message'])): ?>
                    <span class="error"><?= $errors['message'] ?></span>
                <?php endif; ?>
            </div>
            
            <button type="submit" class="btn-submit">Send Message</button>
        </form>
    <?php endif; ?>
</body>
</html>
            

This example demonstrates a common pattern for form handling in PHP:

  1. Check if the form was submitted
  2. Validate the inputs
  3. Either show success message or redisplay the form with errors
  4. Use the null coalescing operator (??) to maintain form values on validation failure
  5. Display specific error messages for each field

Dynamically Generated Form Elements


<!-- Creating a dropdown from database data -->
<div class="form-group">
    <label for="category">Category:</label>
    <select id="category" name="category">
        <option value="">Select a category</option>
        <?php foreach ($categories as $category): ?>
            <option value="<?= $category['id'] ?>" <?= (isset($_POST['category']) && $_POST['category'] == $category['id']) ? 'selected' : '' ?>>
                <?= htmlspecialchars($category['name']) ?>
            </option>
        <?php endforeach; ?>
    </select>
    <?php if (isset($errors['category'])): ?>
        <span class="error"><?= $errors['category'] ?></span>
    <?php endif; ?>
</div>

<!-- Dynamically generated checkboxes -->
<div class="form-group">
    <label>Interests:</label>
    <div class="checkbox-group">
        <?php foreach ($interests as $key => $label): ?>
            <label class="checkbox-label">
                <input type="checkbox" name="interests[]" value="<?= $key ?>" 
                       <?= (isset($_POST['interests']) && in_array($key, $_POST['interests'])) ? 'checked' : '' ?>>
                <?= htmlspecialchars($label) ?>
            </label>
        <?php endforeach; ?>
    </div>
    <?php if (isset($errors['interests'])): ?>
        <span class="error"><?= $errors['interests'] ?></span>
    <?php endif; ?>
</div>
            

This example shows how to dynamically generate form elements from arrays of data, and how to maintain their selected/checked state when redisplaying the form after validation failures.

Best Practices for PHP in HTML

While PHP's ability to mix directly with HTML is powerful, it can lead to messy code if not used carefully. Here are some best practices to follow:

Use Alternative Syntax in Templates

The alternative syntax for control structures (if:, foreach:, endif;, endforeach;) is more readable in HTML templates than the curly brace syntax.


<!-- Preferred in HTML templates -->
<?php if ($condition): ?>
    <div>HTML content</div>
<?php endif; ?>

<!-- Less readable in HTML templates -->
<?php if ($condition) { ?>
    <div>HTML content</div>
<?php } ?>
            

Separate Logic from Presentation

Try to separate complex PHP logic from your HTML templates. Do the heavy lifting before the HTML begins:


<?php
// Process data before the HTML
$users = getUsersFromDatabase();
$filteredUsers = [];

foreach ($users as $user) {
    if ($user['active'] && $user['role'] === 'customer') {
        $filteredUsers[] = $user;
    }
}

// Sort users by name
usort($filteredUsers, function($a, $b) {
    return strcmp($a['name'], $b['name']);
});

// Calculate totals
$totalUsers = count($filteredUsers);
$totalOrders = calculateTotalOrders($filteredUsers);
?>

<!-- Now the HTML with simpler PHP -->
<div class="user-dashboard">
    <h2>Active Customers (<?= $totalUsers ?>)</h2>
    <p>Total Orders: <?= $totalOrders ?></p>
    
    <table>
        <!-- Simple loop in the HTML -->
        <?php foreach ($filteredUsers as $user): ?>
            <tr>
                <td><?= htmlspecialchars($user['name']) ?></td>
                <td><?= htmlspecialchars($user['email']) ?></td>
            </tr>
        <?php endforeach; ?>
    </table>
</div>
            

Use Helper Functions for Formatting

Create helper functions to handle common formatting tasks to keep your templates clean:


<?php
// Helper functions
function formatCurrency($amount) {
    return '$' . number_format($amount, 2);
}

function formatDate($date, $format = 'M j, Y') {
    return date($format, strtotime($date));
}

function e($text) {
    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}
?>

<!-- Using helper functions in template -->
<div class="product">
    <h2><?= e($product['name']) ?></h2>
    <p class="price"><?= formatCurrency($product['price']) ?></p>
    <p>Added on <?= formatDate($product['created_at']) ?></p>
</div>
            

Consider a Template Engine for Complex Projects

For larger projects, consider using a dedicated template engine like Twig or Blade, which offer more features and better separation of concerns:


<!-- Example of Twig syntax -->
<div class="products">
    {% if products|length > 0 %}
        {% for product in products %}
            <div class="product">
                <h2>{{ product.name }}</h2>
                <p>{{ product.price|currency }}</p>
            </div>
        {% endfor %}
    {% else %}
        <p>No products found.</p>
    {% endif %}
</div>
            

Template engines provide benefits like:

Practical Example: Dynamic Website

Let's create a practical example of a simple blog page that demonstrates many of the concepts we've covered in this lecture:


<?php
// blog.php

// In a real application, these would come from a database
$posts = [
    [
        'id' => 1,
        'title' => 'Getting Started with PHP',
        'content' => 'PHP is a powerful server-side scripting language for creating dynamic web pages...',
        'author' => 'Jane Smith',
        'date' => '2025-03-15',
        'tags' => ['PHP', 'Web Development', 'Beginner']
    ],
    [
        'id' => 2,
        'title' => 'Advanced CSS Techniques',
        'content' => 'Learn how to use CSS Grid and Flexbox to create modern layouts...',
        'author' => 'John Doe',
        'date' => '2025-03-10',
        'tags' => ['CSS', 'Web Design', 'Frontend']
    ],
    [
        'id' => 3,
        'title' => 'JavaScript Frameworks Comparison',
        'content' => 'A detailed comparison of React, Vue, and Angular...',
        'author' => 'Alex Johnson',
        'date' => '2025-03-05',
        'tags' => ['JavaScript', 'Frameworks', 'Frontend']
    ]
];

// Get tag filter from query string
$tagFilter = isset($_GET['tag']) ? htmlspecialchars($_GET['tag']) : null;

// Filter posts by tag if filter is set
$filteredPosts = $posts;
if ($tagFilter) {
    $filteredPosts = array_filter($posts, function($post) use ($tagFilter) {
        return in_array($tagFilter, $post['tags']);
    });
}

// Helper functions
function formatDate($date) {
    return date('F j, Y', strtotime($date));
}

function excerpt($text, $length = 100) {
    if (strlen($text) <= $length) {
        return $text;
    }
    return substr($text, 0, $length) . '...';
}

function e($text) {
    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}

// Get all unique tags
$allTags = [];
foreach ($posts as $post) {
    foreach ($post['tags'] as $tag) {
        $allTags[$tag] = true;
    }
}
$allTags = array_keys($allTags);
sort($allTags);
?>

<!DOCTYPE html>
<html>
<head>
    <title><?= $tagFilter ? "Posts tagged '{$tagFilter}'" : 'My Blog' ?></title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <header>
        <h1>My Web Development Blog</h1>
        <nav>
            <a href="blog.php">Home</a>
            <a href="about.php">About</a>
            <a href="contact.php">Contact</a>
        </nav>
    </header>
    
    <main class="blog-container">
        <aside class="sidebar">
            <div class="tags-widget">
                <h2>Tags</h2>
                <ul class="tag-list">
                    <li><a href="blog.php" class="<?= $tagFilter ? '' : 'active' ?>">All Posts</a></li>
                    <?php foreach ($allTags as $tag): ?>
                        <li>
                            <a href="blog.php?tag=<?= urlencode($tag) ?>" 
                               class="<?= ($tagFilter === $tag) ? 'active' : '' ?>">
                                <?= e($tag) ?>
                            </a>
                        </li>
                    <?php endforeach; ?>
                </ul>
            </div>
        </aside>
        
        <section class="posts">
            <?php if ($tagFilter): ?>
                <div class="filter-notice">
                    <p>Showing posts tagged with: <span class="tag"><?= e($tagFilter) ?></span></p>
                    <a href="blog.php">Clear filter</a>
                </div>
            <?php endif; ?>
            
            <?php if (count($filteredPosts) > 0): ?>
                <?php foreach ($filteredPosts as $post): ?>
                    <article class="post">
                        <h2><a href="post.php?id=<?= $post['id'] ?>"><?= e($post['title']) ?></a></h2>
                        
                        <div class="post-meta">
                            <span class="author">By <?= e($post['author']) ?></span>
                            <span class="date">Published on <?= formatDate($post['date']) ?></span>
                        </div>
                        
                        <div class="post-content">
                            <p><?= e(excerpt($post['content'])) ?></p>
                        </div>
                        
                        <div class="post-tags">
                            <?php foreach ($post['tags'] as $tag): ?>
                                <a href="blog.php?tag=<?= urlencode($tag) ?>" class="tag"><?= e($tag) ?></a>
                            <?php endforeach; ?>
                        </div>
                        
                        <a href="post.php?id=<?= $post['id'] ?>" class="read-more">Read More</a>
                    </article>
                <?php endforeach; ?>
            <?php else: ?>
            

No posts found with the tag:

View all posts

This example showcases many of the concepts we've covered:

In a real-world application, the data would come from a database rather than being hardcoded, but the PHP/HTML integration techniques would remain the same.

Security Considerations

When embedding PHP in HTML, security must be a top priority. Here are key security considerations:

Always Escape Output

Any user-provided or database-retrieved content must be escaped before output to prevent Cross-Site Scripting (XSS) attacks:


<!-- Unsafe (vulnerable to XSS) -->
<div class="comment">
<?= $comment['text'] ?>
</div>

<!-- Safe -->
<div class="comment">
<?= htmlspecialchars($comment['text'], ENT_QUOTES, 'UTF-8') ?>
</div>
      

Consider creating a helper function for escaping output to make it easier and more consistent:


<?php
function e($text) {
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}
?>

<!-- Then use it throughout your templates -->
<div class="comment">
<?= e($comment['text']) ?>
</div>
      

Validate and Sanitize Inputs

Always validate and sanitize user inputs before processing them:


<?php
// Form processing
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Sanitize inputs
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$username = trim(strip_tags($_POST['username']));

// Validate inputs
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  $errors['email'] = 'Invalid email format';
}

if (strlen($username) < 3 || strlen($username) > 20) {
  $errors['username'] = 'Username must be between 3 and 20 characters';
}
}
?>
      

Use Prepared Statements for Database Queries

When integrating with databases, always use prepared statements to prevent SQL injection:


<?php
// Display products from a category (safely)
$categoryId = $_GET['category_id'] ?? 0;

// Using PDO with prepared statements
$db = new PDO('mysql:host=localhost;dbname=mystore', 'username', 'password');
$stmt = $db->prepare('SELECT * FROM products WHERE category_id = ?');
$stmt->execute([$categoryId]);
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

<!-- Then use the data safely in your HTML -->
<div class="products">
<?php foreach ($products as $product): ?>
  <div class="product">
      <h3><?= e($product['name']) ?></h3>
      <p>$<?= number_format($product['price'], 2) ?></p>
  </div>
<?php endforeach; ?>
</div>
      

Protect Against CSRF Attacks

For forms that perform actions (especially those that modify data), use CSRF tokens to prevent Cross-Site Request Forgery:


<?php
// Start session if not already started
session_start();

// Generate CSRF token if none exists
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Check CSRF token on form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
  die('CSRF token validation failed');
}

// Process form...
}
?>

<!-- Include the token in your form -->
<form method="post" action="">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">

<!-- Form fields -->
<input type="text" name="username">
<button type="submit">Submit</button>
</form>
      

Performance Considerations

When embedding PHP in HTML, also keep performance in mind:

Minimize Database Queries

Fetch all needed data before starting HTML output, rather than making queries within loops:


<!-- Inefficient approach (query in loop) -->
<ul class="users">
<?php foreach ($userIds as $userId): ?>
  <?php $user = getUserById($userId); // Database query for each user ?>
  <li><?= e($user['name']) ?></li>
<?php endforeach; ?>
</ul>

<!-- Efficient approach (single query) -->
<?php
$users = getAllUsersByIds($userIds); // Single database query
?>
<ul class="users">
<?php foreach ($users as $user): ?>
  <li><?= e($user['name']) ?></li>
<?php endforeach; ?>
</ul>
      

Output Buffering

For complex pages, consider using output buffering to capture all output and send it to the browser at once:


<?php
// Start output buffering
ob_start();

// Process data and generate HTML
// ...

// Send output to browser all at once
$content = ob_get_clean();
echo $content;
?>
      

Caching

For pages with relatively static content, implement caching to avoid regenerating the same content repeatedly:


<?php
// Simple file-based caching
$cacheFile = 'cache/homepage.html';
$cacheTime = 3600; // 1 hour

if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
// Serve from cache if cache exists and is fresh
readfile($cacheFile);
exit;
}

// Start output buffering for new content
ob_start();
?>

<!-- HTML content with PHP -->
<!DOCTYPE html>
<html>
<!-- ... page content ... -->
</html>

<?php
// Save to cache
$content = ob_get_clean();
file_put_contents($cacheFile, $content);

// Output to browser
echo $content;
?>
      

Practice Activities

Activity 1: Dynamic Product Listing

Create a PHP webpage that displays a list of products with the following features:

  1. Define an array of products with properties like name, price, description, and category
  2. Create a sidebar that displays all product categories
  3. Allow filtering products by category via a query parameter
  4. Implement a simple layout with header, sidebar, main content, and footer
  5. Format prices with proper currency symbols
  6. Ensure all output is properly escaped

Activity 2: Contact Form with Validation

Create a contact form page that:

  1. Includes fields for name, email, subject, and message
  2. Validates all fields on form submission
  3. Displays appropriate error messages next to each invalid field
  4. Preserves user input on validation failure
  5. Shows a success message when all validation passes
  6. Implements CSRF protection

Activity 3: Dynamic Navigation Menu

Create a reusable navigation component that:

  1. Defines the navigation structure in a PHP array
  2. Generates menu items dynamically based on the array
  3. Highlights the current page in the navigation
  4. Supports dropdown submenus for categories
  5. Stores the component in a separate file for inclusion in multiple pages
  6. Allows customization via parameters passed to the include file

Summary

In this lecture, we've explored the powerful integration of PHP and HTML:

This integration is the foundation of PHP web development, allowing you to create dynamic, data-driven websites. While modern development often employs frameworks with dedicated templating engines, understanding the core PHP/HTML integration is essential for any PHP developer.

Further Reading