我目前只有一个只包含两个元素的小型搜索表单:名为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 if
似乎有很多重复性和非生产性,特别是如果我有很多要处理的列。
我尝试的第一件事是参数绑定 - ... WHERE ? LIKE ...
和$prep->bind_param('ss', $param, $search)
- 但是它不起作用(我仍然不知道为什么)。
有没有办法以更聪明的方式做到这一点?
答案 0 :(得分:3)
如果您为每个参数使用相同的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(“%”,?,“%”) - 最好将值与前面的百分比绑定。
答案 1 :(得分: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();
}
没有测试过它,但它似乎是一个明智的解决方案。
答案 2 :(得分:1)
您不能将占位符用于列名,因此您必须正常连接列名。然而,不是仅仅使用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.';
还要注意删除concat
语句,而是在PHP中连接。这对于预处理语句很重要,因为一旦它到达服务器它实际上并没有组合它们(因此保护预准备语句),所以除非使用$search
字符串发送通配符,否则它将无法正常工作。 p>