简体   繁体   English

如何使用mysqli将变量传递给WHERE子句?

[英]How can I pass a variable to a WHERE clause using mysqli?

I currently have a small search form with only two elements: a text input named search and a "select" box named param . 我目前有一个只有两个元素的小搜索表单:一个名为search的文本输入和一个名为param的“select”框。 The option selected within that box should be used as a parameter to choose which table column in my DB would be fetched. 在该框中选择的选项应该用作参数,以选择我的数据库中的哪个表列将被提取。

Using mysql_ functions, something like this could be done: 使用mysql_函数,可以这样做:

$param  = $_POST['param' ];
$search = $_POST['search'];

$query = 'SELECT * FROM table WHERE $param LIKE "%$search%"';

But I can't get it to work with the mysqli_ syntax. 但我无法使用mysqli_语法。 I am trying to use prepared statements, but the best I've done so far is this: 我正在尝试使用准备好的语句,但到目前为止我所做的最好的是:

$param  = $_POST['param' ];
$search = $_POST['search'];

if($param == 'first_name')
{
    if($prep = $link->prepare('SELECT * FROM table
                               WHERE first_name
                               LIKE CONCAT("%", ?, "%")'))
    {
        $prep->bind_param('s', $search);
        $prep->execute();
        $prep->bind_result($first_name, $last_name);

        while($prep->fetch())
            echo $first_name . ' ' . $last_name;

        $prep->close();
     }
     else
         echo 'Error while preparing statement.';
}
else if($param == 'last_name')
{
    ...
}

But just using a bunch of else if s seems a lot repetitive and unproductive, specially if I have lots of columns to handle. 但是,如果我看起来很多重复和非生产性的话,只是使用一堆else if ,特别是如果我有很多列要处理。

The first thing I tried was parameter binding - ... WHERE ? LIKE ... 我尝试的第一件事是参数绑定 - ... WHERE ? LIKE ... ... WHERE ? LIKE ... and $prep->bind_param('ss', $param, $search) -, but it didn't work (and I still don't know why). ... WHERE ? LIKE ...$prep->bind_param('ss', $param, $search) - 但是它不起作用(我仍然不知道为什么)。

Is there a way of doing it in a more intelligent way? 有没有办法以更聪明的方式做到这一点?

If you are using the same SQL code for every param, just create a hash of possible params: (CGI param name => table column name) 如果您为每个参数使用相同的SQL代码,只需创建可能的参数的散列: (CGI param name => table column name)

$params = array(
    'first_name' => 'first_name',
    'last_name' => 'last_name',
);

It's much better from a security point of view as you are protected from SQL injection. 从安全的角度来看,这是更好的,因为您可以防止SQL注入。

Then get the column name from the hash and put it into the query - and you'll get rid of the if-s: 然后从哈希中获取列名并将其放入查询中 - 您将摆脱if-s:

$name = $params[$param];
$sql = "SELECT * FROM table
WHERE 
$name LIKE ?";

if($prep = $link->prepare($sql))
{
    $prep->bind_param('s', "%$search%");
    ...

As @Akam said, no need to CONCAT("%", ?, "%") in the query - it's better to bind the value with percents right ahead. 正如@Akam所说,在查询中不需要CONCAT(“%”,?,“%”) - 最好将值与前面的百分比绑定。

According to this example in the PHP manual 根据PHP手册中的这个例子

http://www.php.net/manual/en/mysqli-stmt.bind-param.php#108790 http://www.php.net/manual/en/mysqli-stmt.bind-param.php#108790

You seem to be best to add the '%' to the string variable you are binding - rather than in the query eg in your example: 您似乎最好将'%'添加到您要绑定的字符串变量中 - 而不是在查询中,例如在您的示例中:

if($prep = $link->prepare('SELECT * FROM table
                           WHERE first_name
                           LIKE ?'))
{
    $search='%'.$search.'%';
    $prep->bind_param('s', $search);
    $prep->execute();
    $prep->bind_result($first_name, $last_name);

    while($prep->fetch())
        echo $first_name . ' ' . $last_name;

    $prep->close();
 }

Haven't tested it but it seems like a sensible solution. 没有测试它,但它似乎是一个明智的解决方案。

You can't use placeholders for column names, so you'll have to concatenate the column names normally. 您不能使用占位符作为列名,因此您必须正常连接列名。 However, instead of just escaping it with mysqli, because you have a limited set of columns I'd suggest a while list approach: 然而,不是仅仅使用mysqli转义它,因为你有一组有限的列我建议使用while列表方法:

$allowed_params = array('first_name', 'last_name', etc);

$param  = $_POST['param' ];
$search = $_POST['search'];


if(!in_array($param, $allowed_params))
    die("Uh oh, the request seems to have an invalid param!");

if($prep = $link->prepare('SELECT * FROM table
                           WHERE ' . $param . '
                           LIKE ?'))
{
    $prep->bind_param('s', '%' . $search . '%');
    $prep->execute();
    $prep->bind_result($first_name, $last_name);

    while($prep->fetch())
        echo $first_name . ' ' . $last_name;

    $prep->close();
}
else
    echo 'Error while preparing statement.';

Also note the removal of the concat statement, and instead concatenating in PHP. 还要注意删除concat语句,而是在PHP中连接。 This is important for prepared statements as once it gets to the server it's not actually combining them (thus the protection of prepared statements), so it won't work properly unless the wildcards are sent with the $search string. 这对于预处理语句很重要,因为一旦它到达服务器它实际上并没有组合它们(因此保护预准备语句),所以除非使用$search字符串发送通配符,否则它将无法正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM