0

I am trying to do a search across 29 fields in my database in my PHP project. I am using mysqli to connect to my database. My query works fine when I do not try to use bind_param(), but fails when I do with the error:

PHP Warning:  mysqli_stmt::bind_param() [<a href='mysqli-stmt.bind-param'>mysqli-stmt.bind-param</a>]: Number of variables doesn't match number of parameters in prepared statement in /search.php on line 6

My code is as follows:

<?php 
$find = $_POST['find'];
if (strcasecmp($_POST['in'], 'users') == 0) {

$query = $db->prepare("SELECT u.id, u.group_id, u.username, u.email, m.credits, m.first_name, m.last_name, m.address1, m.address2, m.city, m.state, m.country, m.zipcode, m.about, m.account_status, m.vacation_status FROM kf_users u JOIN kf_usermeta m ON u.id = m.id WHERE u.id LIKE  '%?%' OR u.group_id LIKE  '%?%' OR u.ip_address LIKE  '%?%' OR u.username  LIKE  '%?%' OR u.password LIKE  '%?%' OR u.salt LIKE  '%?%' OR u.email LIKE  '%?%' OR u.activation_code LIKE  '%?%' OR u.forgotten_password_code LIKE  '%?%' OR u.remember_code LIKE  '%?%' OR u.created_on LIKE  '%?%' OR u.last_login LIKE '%?%' OR u.active LIKE  '%?%' OR u.FUID LIKE  '%?%' OR m.id LIKE  '%?%' OR m.credits LIKE  '%?%' OR m.rating LIKE  '%?%' OR m.user_id LIKE  '%?%' OR m.first_name LIKE  '%?%' OR m.last_name LIKE  '%?%' OR m.address1 LIKE  '%?%' OR m.address2 LIKE  '%?%' OR m.city LIKE  '%?%' OR m.state LIKE  '%?%' OR m.country LIKE  '%?%' OR m.zipcode LIKE  '%?%' OR m.about LIKE  '%?%' OR m.account_status LIKE  '%?%' OR m.vacation_status LIKE '%?%'");
$query->bind_param('sssssssssssssssssssssssssssss',$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find,$find);
$query->execute();
$query->bind_result($id, $group, $username, $email, $credits, $first_name, $last_name, $address1, $address2, $city, $state, $country, $zipcode, $about, $account_status, $vacation_status);

while ($query->fetch()) {
    $result['id'] = $id;
    $result['group'] = $group;
    $result['username'] = $username;
    $result['email'] = $email;
    $result['credits'] = $credits;
    $result['first_name'] = $first_name;
    $result['last_name'] = $last_name;
    $result['address1'] = $address1;
    $result['address2'] = $address2;
    $result['city'] = $city;
    $result['state'] = $state;
    $result['country'] = $country;
    $result['zipcode'] = $zipcode;
    $result['about'] = $about;
    $result['account_status'] = $account_status;
    $result['vacation_status'] = $vacation_status; 
    $output[] = $result;
}

$query->close();

}
?>

Again, if I comment out my bind_param() line, and replace the ? in my query with my search term the data is returned, where as is I get an error and no data. Anyone have any ideas on what might be the issue here?

3 Answers 3

3

You have 29 ?'s is your query, 29 s data-type entries in your bind_param list, and 29 $find variables to bind, however, when you encapsulate your ? placeholders in quotes - they are no longer placeholders, they are simply strings. Therefore, MySQL is seeing zero parameters to be bound and you're attempting to bind 29.

To do a simple LIKE clause using the prepared statement, you would do something like:

$query = $db->prepare("SELECT * FROM some_table WHERE field LIKE ?");
$query->bind_param('s',$find);

In your case, you want to match %$find%. You can do this with:

$query = $db->prepare("SELECT * FROM some_table WHERE field LIKE ?");
$query->bind_param('s', '%'.$find.'%');

Or even more complicated, you can use CONCAT() on every parameter:

$query = $db->prepare("SELECT * FROM some_table WHERE field LIKE CONCAT('%', ?, '%')");
$query->bind_param('s',$find);

A copy+paste using your existing code and the first method ('%'.$find.'%'):

$query = $db->prepare("SELECT u.id, u.group_id, u.username, u.email, m.credits, m.first_name, m.last_name, m.address1, m.address2, m.city, m.state, m.country, m.zipcode, m.about, m.account_status, m.vacation_status FROM kf_users u JOIN kf_usermeta m ON u.id = m.id WHERE u.id LIKE ? OR u.group_id LIKE ? OR u.ip_address LIKE ? OR u.username  LIKE ? OR u.password LIKE ? OR u.salt LIKE ? OR u.email LIKE ? OR u.activation_code LIKE ? OR u.forgotten_password_code LIKE ? OR u.remember_code LIKE ? OR u.created_on LIKE ? OR u.last_login LIKE ? OR u.active LIKE ? OR u.FUID LIKE ? OR m.id LIKE ? OR m.credits LIKE ? OR m.rating LIKE ? OR m.user_id LIKE ? OR m.first_name LIKE ? OR m.last_name LIKE ? OR m.address1 LIKE ? OR m.address2 LIKE ? OR m.city LIKE ? OR m.state LIKE ? OR m.country LIKE ? OR m.zipcode LIKE ? OR m.about LIKE ? OR m.account_status LIKE ? OR m.vacation_status LIKE ?");
$query->bind_param('sssssssssssssssssssssssssssss','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%','%'.$find.'%');
Sign up to request clarification or add additional context in comments.

1 Comment

Emphasize on "when you encapsulate your ? placeholders in quotes - they are no longer placeholders, they are simply strings", that's why bind_param wasn't working for me.
2

Binding parameters is not the same as string interpolation; you cannot just replace your variable with ?, nor should you quote them. The placeholder is for the entire value.

Instead, you should prepare your query like this

$query = $db->prepare('SELECT ... WHERE u.id LIKE ? OR u.group_id LIKE ? ... ');

Then wrap your value in the wildcard characters

$find = '%' . $find . '%';

Update

I would very strongly suggest using PDO instead of MySQLi. With it you can use named placeholders, for example

$stmt = $pdo->prepare('SELECT ... WHERE u.id LIKE :term OR u.group_id LIKE :term ... ');
$find = '%' . $find . '%';
$stmt->bindParam('term', $find);
$stmt->execute();

This way, you can reuse the same placeholder throughout your query

Comments

-1

If this is not working then you are probably using mariadb instead of mysql. This problemm is a subtle difference between the two.

What I have done with my code is to alter it with:

$search_text=$db->real_escape_string($search_text);
$stmt=$db->prepare("SELECT * FROM rentals WHERE search_text LIKE '%{$search_text}%'");
//TODO Put the bind_param back when it works someday; plus take out the escape.
//$stmt=$db->prepare("SELECT * FROM rentals WHERE search_text LIKE ?");
//$stmt->bind_param('s', '%'.$search_text.'%');
$stmt->execute();

Crude but for the time being a working solution.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.