You are correct that you can't use mysql_real_escape_string()
when interpolating a whole subquery into your location query.
$name = $_POST['name'];
$user = "Select user from user where name = $name"
$user_esc = mysql_real_escape_string($user); -- WRONG
$loc = "Select * from location where user = $user"
Advice to defend against SQL injection often comes down to "use query parameters" and that is correct in many cases, but in this case it doesn't work.
The escape-string function and bound query parameters are both used only for protecting individual values in SQL expressions. Neither of these are useful for other parts of a dynamic SQL query:
- Identifiers like table names or column names
- Lists of values (for example inside an
IN(...)
predicate)
- SQL keywords
- SQL expressions
- Whole SQL subqueries, as in your case.
In your case, your subquery is a fixed string under the control of your app, except for the $name variable. If you escape that variable then it's safe from SQL injection.
$name = $_POST['name'];
$name_esc = mysql_real_escape_string($name);
$user_query = "Select user from user where name = '$name_esc'"
Then you can use that subquery as part of the second query, and there is no risk of SQL injection.
$loc_query = "Select * from location where user IN ($user_query)"
By the way I made two small changes:
- Put the subquery inside parentheses
- Use
IN( )
instead of =
. If the subquery can return more than one row in its result, it's not allowed to use =
.
I would also recommend you learn how to use joins in SQL. This is an ordinary and recommended way to use SQL. Usually if the tables are indexed correctly, a query using join has better performance than the query using a subquery, even if both queries produce the same result. Here's an example:
$name = $_POST['name'];
$name_esc = mysql_real_escape_string($name);
$loc_query = "Select loc.* from user join loc using (user)
where user.name = '$name_esc'";
I'll probably get downvoted for giving you a solution that works with mysql_real_escape_string(), because that function is deprecated and it is removed from current versions of PHP.
I do recommend upgrading to the current version of PHP and I do recommend using PDO and query parameters. They're easier, safer, and have better performance.
$loc_query = "Select loc.* from user join loc using (user)
where user.name = ?";
$stmt = $pdo->prepare($loc_query);
$stmt->execute( [ $_POST['name'] ] );
No need to escape the post variable when you use query parameters.
You will also find PHP 7+ generally has much better performance than PHP 5.x.
It's not true that you can't upgrade. It would just take some work.