Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Query the category records, then generate one HTML <option> for each row. Use the category’s database ID as the submitted value and its name as the visible label, escaping both before writing them into HTML.

Build the dropdown from database rows

This example assumes a configured PDO connection in $pdo and a table named categories with id and name columns. Replace those names with the ones in your schema.

<?php
$stmt = $pdo->query('SELECT id, name FROM categories ORDER BY name');
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

<label for="category">Category</label>
<select name="category_id" id="category" required>
    <option value="">Choose a category</option>
    <?php foreach ($categories as $category): ?>
        <option value="<?= htmlspecialchars((string) $category['id'], ENT_QUOTES, 'UTF-8') ?>">
            <?= htmlspecialchars($category['name'], ENT_QUOTES, 'UTF-8') ?>
        </option>
    <?php endforeach; ?>
</select>

PDO::query() fits this fixed SQL statement because it has no user-provided values. The query sorts the records by name; the loop then renders each row as an option. PHP’s PDO::query documentation describes executing a query that does not require input parameters.

The label is associated with the control through its matching for and id values. The empty prompt gives the user an initial choice; keep required only when selecting a category is mandatory. The MDN reference for the HTML select element explains the select control and its options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use prepared statements when the query has input

If the category query depends on a value supplied by a user—for example, a selected parent category—do not concatenate that value into the SQL string. Prepare the statement and bind the value:

$stmt = $pdo->prepare('SELECT id, name FROM categories WHERE parent_id = :parent_id ORDER BY name');
$stmt->execute(['parent_id' => $parentId]);
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);

Parameter markers bind values, not SQL identifiers such as table or column names. PHP’s PDO::prepare documentation advises binding user input instead of including it directly in a query. This protects the SQL context; it does not replace escaping values when they are later inserted into HTML.

Escape database values in the HTML output

The ID is placed inside a quoted HTML attribute, while the category name becomes visible text. Escape each value where it enters HTML, as in the example, using htmlspecialchars with ENT_QUOTES and the explicit UTF-8 encoding. This applies even if an ID is not numeric or is not guaranteed to contain only safe characters. See PHP’s htmlspecialchars documentation.

SQL parameterization and HTML escaping address different risks: bind dynamic values for SQL, then escape output for the HTML context. A prepared statement alone does not make a category name safe to print in a page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Handle empty results, large lists, and saved selections

No categories returned

fetchAll(PDO::FETCH_ASSOC) returns the remaining rows as an array indexed by column name. If the query returns no rows, the array is empty and the loop adds no category options; the prompt remains visible. For a table with a very large result set, consider limiting or redesigning the selection rather than loading every row at once: PHP notes that fetchAll() can consume substantial resources. See PDOStatement::fetchAll documentation.

Keep an existing selection

When editing a record, compare each category ID with the validated ID you intend to preserve and add selected to the matching option. Escape the ID used in the value attribute and validate the selection before relying on it.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Validate the submitted category on the server

Submitting an option sends its value, not its visible label. Use the stable category ID as that value, then validate the received ID against the records and permissions that apply when processing the form. A dropdown is a user interface, not proof that a submitted identifier is valid or that the user is allowed to use it.

This example covers rendering the dropdown, not database connection setup. It requires an existing PDO connection and an installed driver for the database in use; the connection details and actual table and column names depend on the application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.