除了使用IN查询之外,您还有两个选项可以执行此操作,因为在IN查询中存在SQL注入漏洞的风险 . 您可以使用 looping 获取所需的确切数据,也可以使用 OR case查询
1. SELECT *
FROM galleries WHERE id=1 or id=2 or id=5;
2. $ids = array(1, 2, 5);
foreach ($ids as $id) {
$data[] = SELECT *
FROM galleries WHERE id= $id;
}
function escape($string)
{
// Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
return mysqli_real_escape_string($db, $string);
}
$galleryIds = [1, '2', 'Vitruvian Man'];
$ids = array_filter($galleryIds, function($n){return (is_numeric($n));});
$ids = implode(', ', $ids);
$sql = "SELECT * FROM galleries WHERE id IN ({$ids})";
// output: 'SELECT * FROM galleries WHERE id IN (1, 2)'
$statement = $pdo->prepare($sql);
$statement->execute();
26
没有PDO的安全方式:
$ids = array_filter(array_unique(array_map('intval', (array)$ids)));
if ($ids) {
$query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');';
}
即现在你应该安全地使用 $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
4
假设你事先正确消毒你的输入......
$matches = implode(',', $galleries);
然后只需调整您的查询:
SELECT *
FROM galleries
WHERE id IN ( $matches )
根据您的数据集适当地引用值 .
2
因为原始问题涉及数字数组而我使用的是字符串数组,所以我无法使给定的示例工作 .
我发现需要将每个字符串封装在单引号中以使用 IN() 函数 .
这是我的解决方案
foreach($status as $status_a) {
$status_sql[] = '\''.$status_a.'\'';
}
$status = implode(',',$status_sql);
$sql = mysql_query("SELECT * FROM table WHERE id IN ($status)");
正如您所看到的,第一个函数在 single quotes (\') 中包装每个数组变量,然后内爆数组 .
18 回答
对于具有转义功能的MySQLi:
对于准备好声明的PDO:
Using PDO: [1]
Using MySQLi [2]
说明:
使用SQL IN()运算符检查给定列表中是否存在值 .
一般来说,它看起来像这样:
我们可以构建一个表达式,从数组中放入
()
. 请注意,括号内必须至少有一个值,否则MySQL将返回错误;这相当于确保我们的输入数组至少有一个值 . 为了防止SQL注入攻击,首先为每个输入项生成?
以创建参数化查询 . 这里我假设包含你的id的数组被称为$ids
:给定三个项目的输入数组
$select
将如下所示:再次注意,输入数组中的每个项目都有一个
?
. 然后我们将使用PDO或MySQLi来准备和执行上述查询 .将IN()运算符与字符串一起使用
由于绑定参数,很容易在字符串和整数之间进行更改 . 对于PDO,不需要进行任何更改;对于MySQLi,如果需要检查字符串,请将
str_repeat('i',
更改为str_repeat('s',
.[1]:为简洁起见,我省略了一些错误检查 . 您需要检查每个数据库方法的常见错误(或将数据库驱动程序设置为抛出异常) .
[2]:需要PHP 5.6或更高版本 . 为了简洁起见,我省略了一些错误检查 .
整型:
字符串:
作为Flavius Stef's answer,您可以使用
intval()
来确保所有id
都是int值:使用:
一个简单的
for each
循环将起作用 .Flavius/AvatarKava's way更好,但请确保没有数组值包含逗号 .
除了使用IN查询之外,您还有两个选项可以执行此操作,因为在IN查询中存在SQL注入漏洞的风险 . 您可以使用 looping 获取所需的确切数据,也可以使用 OR case查询
防止SQL注入的基本方法是:
使用预准备语句和参数化查询
转义不安全变量中的特殊字符
使用预准备语句和参数化查询查询被认为是更好的做法,但如果您选择转义字符方法,那么您可以尝试下面的示例 .
您可以使用
array_map
为$galleries
中的每个元素添加单引号来生成查询:生成的$ sql var将是:
更安全 .
我们应该处理SQL injection漏洞和空洞的情况 . 我将如下处理两者 .
对于纯数字数组,请在每个元素上使用相应的类型转换,即
intval
或floatval
或doubleval
. 对于字符串类型mysqli_real_escape_string(),如果您愿意,也可以应用于数值 . MySQL允许数字和日期变体作为字符串 .要在传递给查询之前适当地转义值,请创建类似于以下的函数:
这样的功能很可能已经在您的应用程序中可用,或者您已经创建了一个 .
清理字符串数组,如:
可以使用
intval
或floatval
或doubleval
来清理数字数组,如果合适的话:然后最后构建查询条件
or
由于数组有时也可能为空,如
$galleries = array();
,因此我们应注意IN ()
不允许空列表 . 也可以使用OR
,但问题仍然存在 . 所以上面的检查,count($values)
,是为了确保相同 .并将其添加到最终查询:
Col. Shrapnel的SafeMySQL PHP库在其参数化查询中提供了类型提示的占位符,并包含了几个方便的占位符来处理数组 .
?a
占位符将数组扩展为以逗号分隔的转义字符串列表* .例如:
*请注意,由于MySQL执行自动类型强制,因此SafeMySQL会将上面的ID转换为字符串并不重要 - 你仍然会得到正确的结果 .
你可能有表
texts
(T_ID (int), T_TEXT (text))
和表test
(id (int), var (varchar(255)))
在
insert into test values (1, '1,2,3') ;
中,以下将从表文本中输出T_ID IN (1,2,3)
的行:这样,您可以管理简单的n2m数据库关系,而无需额外的表,只使用SQL而无需使用PHP或其他编程语言 .
更多例子:
没有PDO的安全方式:
(array)$ids
将$ids
变量转换为数组array_map
将所有数组值转换为整数array_unique
删除重复的值array_filter
删除零值implode
将所有值加入IN选择如果我们正确地过滤输入数组,我们可以使用这个“WHERE id IN”子句 . 像这样的东西:
如下例所示:
即现在你应该安全地使用
$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
假设你事先正确消毒你的输入......
然后只需调整您的查询:
根据您的数据集适当地引用值 .
因为原始问题涉及数字数组而我使用的是字符串数组,所以我无法使给定的示例工作 .
我发现需要将每个字符串封装在单引号中以使用
IN()
函数 .这是我的解决方案
正如您所看到的,第一个函数在
single quotes (\')
中包装每个数组变量,然后内爆数组 .注意:
$status
在SQL语句中没有单引号 .可能有一种更好的方法来添加引号,但这有效 .
下面是我使用的方法,使用PDO和其他数据的命名占位符 . 为了克服SQL注入,我过滤数组只接受整数值并拒绝所有其他值 .