58

This is my code but it dosn't work:

$param = "%{$_POST['user']}%";
$stmt = $db->prepare("SELECT id,Username FROM users WHERE Username LIKE ?");
$stmt->bind_param("s", $param);
$stmt->execute();
$stmt->bind_result($id,$username);
$stmt->fetch();

This code it doesn't seem to work. I have searched it a lot. Also it may return more than 1 row. So how can I get all the results even if it returns more than 1 row?

4

2 Answers 2

89

Here's how you properly fetch the result

$param = "%{$_POST['user']}%";
$stmt = $db->prepare("SELECT id, username FROM users WHERE username LIKE ?");
$stmt->bind_param("s", $param);
$stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_all(MYSQLI_ASSOC);

Note that starting from PHP 8.2 (with a fallback replacement for 8.0+) a shorter code can be used

$sql = "SELECT id, username FROM users WHERE username LIKE ?";
$result = $db->execute_query($sql, ["%{$_POST['user']}%"]);
$data = $result->fetch_all(MYSQLI_ASSOC);

or, if you prefer the old fetch and bind_result syntax, you can also do:

$param = "%{$_POST['user']}%";
$stmt = $db->prepare("SELECT id,username FROM users WHERE username LIKE ?");
$stmt->bind_param("s", $param);
$stmt->execute();

$stmt->bind_result($id,$username);
while ($stmt->fetch()) {
  echo "Id: {$id}, Username: {$username}";
}

I got the answer directly from the manual here and here.

1
  • 11
    In defense of the OP, neither manual page makes any mention of the LIKE comparison "function"
    – Brad Kent
    Commented Aug 22, 2017 at 0:12
52

From comments it is found that LIKE wildcard characters (_and %) are not escaped by default on Paramaterised queries and so can cause unexpected results.

Therefore when using "LIKE" statements, use this 'negative lookahead' Regex to ensure these characters are escaped :

$param = preg_replace('/(?<!\\\)([%_])/', '\\\$1',$param);

As an alternative to the given answer above you can also use the MySQL CONCAT function thus:

$stmt = $db->prepare("SELECT id,Username FROM users WHERE Username LIKE CONCAT('%',?,'%') ");
$stmt->bind_param("s", $param);
$stmt->execute();

PDO named placeholder version:

$stmt = $db->prepare("SELECT id,Username FROM users WHERE Username LIKE CONCAT('%',:var,'%') ");
$stmt->bind_param("s", ['var'=>$param]);
$stmt->execute();

Which means you do not need to edit your $param value but does make for slightly longer queries.


11
  • Hi is concat safe from sql injection? I'm asking because it has quotes. Thanks Commented Feb 15, 2017 at 23:29
  • @mikevorisis Yes, it's safe because the query is still parameterised (using ?) . the quotes are because MySQL is CONCATenating three strings.
    – Martin
    Commented Feb 16, 2017 at 9:52
  • I upvoted this because I'm pretty sure you can't do 'begins with' or 'ends with' using the accepted answer (as in, you need to use CONCAT).
    – adam rowe
    Commented Jun 15, 2018 at 13:01
  • 4
    @MikeVorisis, CONCAT in prepared statements are safe from injection, but you should be cautious while using LIKE clause in prepared statements. Consider this: $stmt=$db->prepare("SELECT customer` as suggestion WHERE customername LIKE CONCAT('cust_', ?, '%');");` and then $key='J%'; (Or even $key='';), $stmt->bind_param('s', $key);. Now $stmt->execute(); will return ALL records. So, when dealing with Prepared statements having 'LIKE' clause, you still need to handle _ and % in proper way. Even if using prepared statements, escaping like $key='J\%'; is needed. Commented Jul 13, 2018 at 14:28
  • 1
    @mikevorisis Though I think you are probably aware of this and have already taken steps to handle such queries properly, I thought it'd be important to share as it may help others reading this too. Commented Jul 13, 2018 at 14:30

Not the answer you're looking for? Browse other questions tagged or ask your own question.