Free tools Windows power users keep installed
One-click scans. No signup required.
No. A ? placeholder in a mysqli prepared statement represents a data value, not a column name. Keep identifiers such as column names in the SQL statement; bind user-supplied values separately. If a user can choose a column to sort by, map that choice to an allowlist of known column names.
Why a column name cannot be bound
Prepared-statement placeholders represent values in supported SQL positions. They cannot stand in for SQL identifiers such as table or column names, or for syntax such as sort keywords. The PHP Manual for mysqli::prepare states that markers “are not permitted for identifiers (such as table or column names).”
As an Amazon Associate I earn from qualifying purchases.
Write a fixed column directly in the query and bind the value being compared:
$stmt = $mysqli->prepare('SELECT id, email FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$stmt->execute();
Here, email is part of the SQL structure. The placeholder represents the value stored in $email.
#1 Best Overall
How to handle a user-selected sort column
Do not use ORDER BY ? expecting the parameter to become a column name. Instead, translate the user’s selection into one of a fixed set of identifiers controlled by your application, then interpolate only that mapped identifier. Continue binding data values, including the limit:
$sortColumns = [
'name' => 'name',
'created' => 'created_at',
];
$sort = $sortColumns[$_GET['sort'] ?? ''] ?? 'created_at';
$stmt = $mysqli->prepare("SELECT id, name FROM users ORDER BY `$sort` LIMIT ?");
$limit = 25;
$stmt->bind_param('i', $limit);
$stmt->execute();
The lookup prevents an arbitrary request value from being inserted as SQL syntax: unknown choices fall back to the known created_at column. Do not interpolate a raw request value as an identifier. Placeholders remain appropriate for filter values and other data values.
Rank #2
Using bind_param() correctly
bind_param() takes a type string followed by one variable for each placeholder. The PHP Manual documents these type characters:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11ifor integerdfor floatsfor stringbfor blob
For example, this statement binds three values using a matching three-character type string:
$stmt = $mysqli->prepare('INSERT INTO users (name, email, age) VALUES (?, ?, ?)');
$stmt->bind_param('ssi', $name, $email, $age);
$stmt->execute();
Bound arguments are passed by reference, so pass variables rather than literal expressions. For data larger than MySQL’s max_allowed_packet, the PHP Manual for mysqli_stmt::bind_param documents using the b type and mysqli_stmt_send_long_data() to send the data in packets.
Quick Recap
Rank #4
Checks when a prepared statement fails
- Count the SQL placeholders, type-string characters, and bound variables; they must match one-to-one.
- Confirm every placeholder represents a value, not a column or table name.
- Pass variables to
bind_param(), not expressions or literals. - Inspect the statement error and configure mysqli error reporting deliberately. The PHP
mysqli::preparedocumentation describes warning and exception behavior when reporting modes are enabled.
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.




