【问题标题】:How can I pass a variable to a WHERE clause using mysqli?如何使用 mysqli 将变量传递给 WHERE 子句?
【发布时间】:2013-07-24 22:35:50
【问题描述】:

我目前有一个只有两个元素的小型搜索表单:一个名为search 的文本输入和一个名为param 的“选择”框。在该框中选择的选项应用作参数来选择要获取我的数据库中的哪个表列。

使用mysql_ 函数,可以做到这样的事情:

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

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

但我无法让它与mysqli_ 语法一起使用。我正在尝试使用准备好的语句,但到目前为止我做得最好的是:

$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')
{
    ...
}

但是仅仅使用一堆else ifs 似乎很重复并且没有效率,特别是如果我有很多列要处理。

我尝试的第一件事是参数绑定 - ... WHERE ? LIKE ...$prep->bind_param('ss', $param, $search) - 但没有成功(我仍然不知道为什么)。

有没有更智能的方法?

【问题讨论】:

  • +1 可以很好地格式化您的问题
  • ....WHERE ".$param." LIKE....一般我用 sql 语句做什么
  • 据我所知,列名不能使用占位符,这就是它不起作用的原因。
  • bind_param('s', $search) 更改为 bind_param('s', "%$search%") 并将查询更改为 SELECT * FROM table WHERE first_name LIKE ? 另请参阅 user4035 的回答如何为有效列名创建数组
  • @JohnV.: 他在哪里用的?

标签: php binding parameters mysqli where


【解决方案1】:

如果您对每个参数使用相同的 SQL 代码,只需创建可能参数的哈希值:(CGI param name => table column name)

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

从安全角度来看,这要好得多,因为您可以防止 SQL 注入。

然后从哈希中获取列名并将其放入查询中 - 你将摆脱 if-s:

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

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

正如@Akam 所说,无需在查询中使用 CONCAT("%", ?, "%") - 最好将值与前面的百分比绑定。

【讨论】:

  • 不需要在查询中concat,而是:bind_param('s', "%$search%")
  • @Akam 答案改进
  • 高效干净。谢谢!
【解决方案2】:

根据PHP手册中的这个例子

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

您似乎最好将“%”添加到您正在绑定的字符串变量中 - 而不是在查询中,例如在你的例子中:

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();
 }

尚未对其进行测试,但它似乎是一个明智的解决方案。

【讨论】:

  • 这不会解决他使用动态字段名称的问题,但它会在他的解决方案中修复他的示例。
  • 对不起,你是对的,我没有抓住重点。我只需将 $param 字符串替换为查询字符串而不是列名。但是,我会首先对内容进行一些严格的过滤,例如$unsafe_col_name="/[^a-zA-Z0-9\\_]/"; $param=preg_replace("$unsafe_col_name","",$param);
【解决方案3】:

您不能对列名使用占位符,因此您必须正常连接列名。但是,不要仅仅使用 mysqli 对其进行转义,因为您的列集有限,我建议使用 while list 方法:

$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.';

还要注意 concat 语句的删除,而是在 PHP 中进行连接。这对于准备好的语句很重要,因为一旦它到达服务器,它实际上并没有组合它们(因此保护准备好的语句),因此除非通配符与 $search 字符串一起发送,否则它将无法正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    相关资源
    最近更新 更多