Build Your Very First PHP & MySQL Search Engine From Scratch

2026-07-14

Demystifying Database Queries: A Step-by-Step Practical Coding Guide

If you are a self-taught web developer or an ambitious site owner who wants to transition from a “click-and-install” user to a creator, there is no better way to learn than by building a search engine from scratch.

Using third-party plugins is convenient, but coding your own database search script gives you a solid foundation in how dynamic web applications actually function. It forces you to think about user input, database structure, security, and rendering data dynamically.

In this tutorial, we are going to write a lightweight, secure PHP and MySQL search engine from the ground up. We will create a simple MySQL database table, write a clean HTML input form, and connect them using PHP Data Objects (PDO) with prepared statements to keep things safe from hackers.

Step 1: Setting Up the Database and Mock Data

Before we can search through anything, we need a data source. Open your database management tool (like phpMyAdmin, TablePlus, or DBeaver) and run the following SQL commands to create a simple table and populate it with a few dummy articles:

SQL

CREATE TABLE `articles` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `title` VARCHAR(255) NOT NULL,
  `content` TEXT NOT NULL,
  `published_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO `articles` (`title`, `content`) VALUES
('Getting Started with PHP', 'PHP is a popular general-purpose scripting language that is especially suited to web development.'),
('Mastering CSS Grid Layouts', 'CSS Grid Layout is the most powerful layout system available in CSS. It is a 2-dimensional system.'),
('Understanding MySQL Databases', 'MySQL is an open-source relational database management system based on SQL (Structured Query Language).'),
('How to Build a Web App', 'Building a modern web application requires a solid understanding of HTML, CSS, JavaScript, and a backend language.');

This table gives us four articles with titles and content columns that we can query using our script.

Step 2: Designing the HTML Search Form

Next, we need a clean user interface. Create a file named index.php and add this basic HTML5 structure. It includes a standard text input field and a search button:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My First PHP Search Engine</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; line-height: 1.6; }
        .search-box { display: flex; gap: 10px; margin-bottom: 30px; }
        input[type="text"] { flex-grow: 1; padding: 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; }
        button { padding: 10px 20px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
        button:hover { background-color: #0056b3; }
        .result-item { margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #eee; }
        .result-item h3 { margin: 0 0 5px 0; color: #333; }
        .no-results { color: #888; font-style: italic; }
    </style>
</head>
<body>

    <h2>Search Our Database</h2>
    <form action="index.php" method="GET" class="search-box">
        <input type="text" name="query" placeholder="Type keywords..." value="<?php echo isset($_GET['query']) ? htmlspecialchars($_GET['query']) : ''; ?>" required>
        <button type="submit">Search</button>
    </form>

    <!-- PHP Results will load here -->

</body>
</html>

Note: We are using the GET method instead of POST. This is standard for search engines because it allows users to bookmark specific search result pages or share the URL (e.g., index.php?query=php).

Step 3: Writing the PHP & PDO Database Search Logic

Now, let’s insert the PHP code that connects to our database, processes the user’s query securely, and outputs the results. Place this code block directly below the form in your index.php file:

PHP

<?php
// Only run the search if a query has been submitted
if (isset($_GET['query']) && !empty(trim($_GET['query']))) {
    
    // Database credentials
    $host = 'localhost';
    $db   = 'your_database_name';
    $user = 'your_username';
    $pass = 'your_password';
    $charset = 'utf8mb4';

    // PDO options for error handling and security
    $options = [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ];

    $dsn = "mysql:host=$host;dbname=$db;charset=$charset";

    try {
        // Establish connection
        $pdo = new PDO($dsn, $user, $pass, $options);
        
        // Clean and prepare the search keyword
        $searchTerm = trim($_GET['query']);
        
        // Use wildcards (%) for partial matching
        $likeParam = "%" . $searchTerm . "%";

        // SQL Query searching both title and content
        $sql = "SELECT * FROM articles WHERE title LIKE :query OR content LIKE :query ORDER BY id DESC";
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute(['query' => $likeParam]);
        $results = $stmt->fetchAll();

        // Output results
        echo "<h3>Search Results for: '" . htmlspecialchars($searchTerm) . "'</h3>";

        if ($results) {
            foreach ($results as $row) {
                echo "<div class='result-item'>";
                echo "<h3>" . htmlspecialchars($row['title']) . "</h3>";
                echo "<p>" . htmlspecialchars($row['content']) . "</p>";
                echo "</div>";
            }
        } else {
            echo "<p class='no-results'>No articles found matching your criteria.</p>";
        }

    } catch (\PDOException $e) {
        // Log errors securely (do not display raw errors to users in production)
        echo "<p class='no-results'>Something went wrong. Please try again later.</p>";
    }
}
?>

Why This Code is Safe (and Human-Built)

This code avoids a massive security vulnerability: SQL Injection.

If we had simply concatenated the user’s raw text directly into the query—like this: "SELECT * FROM articles WHERE title LIKE '%" . $_GET['query'] . "%'"—an attacker could input special characters to alter the SQL query. They could delete tables, download your entire user database, or bypass login screens.

Instead, we used Prepared Statements with named placeholders (:query). The database treats the user’s input strictly as text, not as executable SQL code.

Furthermore, when rendering the results on the screen, we wrapped the database values in htmlspecialchars(). This prevents Cross-Site Scripting (XSS) attacks, ensuring that even if someone manages to save a malicious HTML or JavaScript snippet in the database, it will display harmlessly on the page as raw text.

You now have a fully functional, highly secure, custom PHP search script. It is lightweight, fast, and ready to be customized with more advanced filters or styling as you see fit.

Comments 0

Leave a Reply

Your email address will not be published. Required fields are marked *