No, it doesn't, use prepared statements as is plus single query functions and proper input validation. The latter one is the default for most functions in PHP (e.g. mysqli::query
Vs. mysqli::multi_query
).
Prepared Statements
Prepared statements will forward the data of a variable and its type separately to your DBMS which in turn will either escape all offending characters on your behalf or parse the data independent of the actual query (depending on the DBMS). There's nothing you have to know about which characters need to be escaped and which don't. This is the most secure way to achieve this.
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli(null, null, null, "database");
$mysqli->prepare("SELECT * FROM `users` WHERE `id` = ?");
$mysqli->bind_param("d", $_GET["id"]);
$mysqli->execute();
// ...
All of this complexity can be abstracted, have a look at e.g. Drupal source code.
Single Query Functions
Single query functions ensure that a query of yours will always only yield a single query that will be passed to the DBMS. Effectively killing any possibility that somebody ends your query and executes another; a typical scenario with SQL injection, example:
<?php
$_GET["id"] = "1;SET foreign_key_checks=0;DROP TABLE users";
$mysqli->multi_query("SELECT * FROM `users` WHERE `id` = {$_GET["id"]}");
Validation
This is perhaps the most important advise and is always important, no matter what you try to achieve. Use PHP's built-in filter_*
functions and check other big project's for validating stuff that isn't covered by these functions.
Combined Example
Let's put it all together.
<?php
// max_range default is PHP_INT_MAX.
$userId = filter_input(INPUT_GET, "id", FILTER_VALIDATE_INT, array(
"options" => array("min_range" => 1),
));
// Contains either a valid integer now or either FALSE or NULL.
if ($userId === null || $userId === false) {
//if (!$userId) {
throw new \InvalidArgumentException();
}
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli(null, null, null, "database");
$stmt = $mysqli->prepare("SELECT `name` FROM `users` WHERE `id` = ?");
%stmt->bind_param("d", $userId);
$stmt->execute();
$stmt->fetch($userName);
$stmt->close();
$mysqli->close();
exit("Hello {$userName} with {$userId}.");
select * from users where id = $id
, so no{"key": "value"}
, which is not valid JSON at all.