使用WHERE子句将数组传递给查询

303 php mysql arrays

给定一组id $galleries = array(1,2,5)我想要一个SQL查询,它在WHERE子句中使用数组的值,如:

SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
Run Code Online (Sandbox Code Playgroud)

如何生成此查询字符串以用于MySQL?

Fla*_*tef 322

谨防!此答案包含严重的SQL注入漏洞.请勿使用此处提供的代码示例,而不确保清除任何外部输入.

$ids = join("','",$galleries);   
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
Run Code Online (Sandbox Code Playgroud)

  • 我只是在此声明之前添加警告:'$ galleries`应该输入验证!Prepared语句无法处理数组AFAIK,因此如果您习惯于绑定变量,则可以在此处轻松进行SQL注入. (21认同)
  • 对于**问题**,这是一个完全有效且安全的答案.谁抱怨它是不安全的 - 如果我用问题中提供的`$ gallery'设置这个特定代码的交易怎么样,你使用前面提到的"sql注入漏洞"来利用它.如果你不能 - 你付我200美元.那个怎么样? (17认同)
  • 标识符仍然是带引号的列表,因此它表示为"WHERE id IN('1,2,3,4')".您需要单独引用每个标识符,否则抛弃括号内的引号. (5认同)
  • 对于像我这样的PHP的新手,可以有人解释,或指向我的资源来解释,为什么这容易注射以及如何正确地做到这一点以防止这种情况?如果在运行下一个查询之前立即从查询生成ID列表,那仍然很危险吗? (2认同)
  • @ ministe2003想象一下,如果`$ galleries`具有以下值:`array('1); SELECT password FROM users;/*')`.如果你没有清理它,查询将读取`SELECT*FROM galleries WHERE id IN(1); SELECT password FROM users;/*)`.将表和列名称更改为数据库中的名称并尝试该查询,查看结果.你会找到一个密码列表作为结果,而不是一个画廊列表.根据数据的输出方式或脚本对意外数据数组的作用,可能会输出到公共视图中... ouch. (2认同)
  • 从SQL注入的两个角度对此有很多热情的评论。这里的 TL;DR 是这个答案确实有效,但是,因为它获取这些原始值并将它们直接放入 SQL,如果上游数据不受信任,您可能会面临 SQL 注入攻击。这个问题还有其他答案,列举了如何避免这个问题。 (2认同)

Lev*_*son 299

使用PDO:[1]

$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
$statement = $pdo->prepare($select);
$statement->execute($ids);
Run Code Online (Sandbox Code Playgroud)

使用MySQLi [2]

$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
$statement = $mysqli->prepare($select);
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
$statement->execute();
$result = $statement->get_result();
Run Code Online (Sandbox Code Playgroud)

说明:

使用SQL IN()运算符检查给定列表中是否存在值.

一般来说,它看起来像这样:

expr IN (value,...)
Run Code Online (Sandbox Code Playgroud)

我们可以构建一个表达式来放置在()数组中.请注意,括号内必须至少有一个值,否则MySQL将返回错误; 这相当于确保我们的输入数组至少有一个值.为了帮助防止SQL注入攻击,首先?为每个输入项生成一个以创建参数化查询.这里我假设包含你的id的数组被调用$ids:

$in = join(',', array_fill(0, count($ids), '?'));

$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
Run Code Online (Sandbox Code Playgroud)

给定三个项目的输入数组$select将如下所示:

SELECT *
FROM galleries
WHERE id IN (?, ?, ?)
Run Code Online (Sandbox Code Playgroud)

再次注意,?输入数组中的每个项都有一个.然后我们将使用PDO或MySQLi来准备和执行上述查询.

使用IN()带字符串的运算符

由于绑定参数,很容易在字符串和整数之间进行更改.对于PDO,不需要进行任何更改; 对于MySQLi str_repeat('i',,str_repeat('s',如果需要检查字符串,则更改为.

[1]:为简洁起见,我省略了一些错误检查.您需要检查每个数据库方法的常见错误(或将数据库驱动程序设置为抛出异常).

[2]:需要PHP 5.6或更高版本.为了简洁起见,我省略了一些错误检查.

  • 什么... $ ids做什么?我得到"语法错误,意外'.'". (6认同)
  • 如果您指的是 `$statement-&gt;bind_param(str_repeat('i', count($ids)), ...$ids);` 那么 `...` 会将 id 从数组扩展为多个参数。如果您指的是“expr IN (value,...)”,那么这仅意味着可以有更多值,例如“WHERE id IN (1, 3, 4)”。只需要至少有一个即可。 (2认同)

小智 56

整型:

$query = "SELECT * FROM `$table` WHERE `$column` IN(".implode(',',$array).")";
Run Code Online (Sandbox Code Playgroud)

字符串:

$query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')";
Run Code Online (Sandbox Code Playgroud)


Ava*_*ava 28

假设你事先正确消毒你的输入......

$matches = implode(',', $galleries);
Run Code Online (Sandbox Code Playgroud)

然后只需调整您的查询:

SELECT *
FROM galleries
WHERE id IN ( $matches ) 
Run Code Online (Sandbox Code Playgroud)

根据您的数据集适当地引用值.


Mat*_*hen 11

使用:

select id from galleries where id in (1, 2, 5);
Run Code Online (Sandbox Code Playgroud)

一个简单的for each循环将起作用.

Flavius/AvatarKava的方式更好,但要确保没有数组值包含逗号.


小智 9

正如Flavius Stef的回答,您可以使用intval()以确保所有id都是int值:

$ids = join(',', array_map('intval', $galleries));  
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
Run Code Online (Sandbox Code Playgroud)


小智 8

对于具有转义功能的MySQLi:

$ids = array_map(function($a) use($mysqli) { 
    return is_string($a) ? "'".$mysqli->real_escape_string($a)."'" : $a;
  }, $ids);
$ids = join(',', $ids);  
$result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)");
Run Code Online (Sandbox Code Playgroud)

对于准备好声明的PDO:

$qmarks = implode(',', array_fill(0, count($ids), '?'));
$sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)");
$sth->execute($ids);
Run Code Online (Sandbox Code Playgroud)


Izh*_*zmi 6

我们应该注意SQL注入漏洞和空条件.我打算如下处理.

对于纯数字数组,使用适当类型的转换即intvalfloatvaldoubleval在每个元件.对于字符串类型mysqli_real_escape_string(),如果您愿意,也可以应用于数值.MySQL允许数字和日期变体作为字符串.

要在传递给查询之前适当地转义值,请创建一个类似于的函数:

function escape($string)
{
    // Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
    return mysqli_real_escape_string($db, $string);
}
Run Code Online (Sandbox Code Playgroud)

这样的功能很可能已经在您的应用程序中可用,或者您已经创建了一个.

清理字符串数组,如:

$values = array_map('escape', $gallaries);
Run Code Online (Sandbox Code Playgroud)

的数字数组可以使用消毒intvalfloatvaldoubleval代替作为合适的:

$values = array_map('intval', $gallaries);
Run Code Online (Sandbox Code Playgroud)

然后最后构建查询条件

$where  = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;
Run Code Online (Sandbox Code Playgroud)

要么

$where  = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;
Run Code Online (Sandbox Code Playgroud)

由于数组有时也可能是空的,$galleries = array();因此我们应该注意IN ()不允许空列表.也可以使用OR,但问题仍然存在.所以上面的检查,count($values)是确保相同的.

并将其添加到最终查询:

$query  = 'SELECT * FROM `galleries` WHERE ' . $where;
Run Code Online (Sandbox Code Playgroud)

提示:如果要在空数组的情况下显示所有记录(无过滤)而不是隐藏所有行,只需在三元组的false部分中将0替换为1即可.


Lit*_*ito 6

没有 PDO 的安全方法:

$ids = array_filter(array_unique(array_map('intval', (array)$ids)));

if ($ids) {
    $query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');';
}
Run Code Online (Sandbox Code Playgroud)
  • (array)$ids$ids变量转换为数组
  • array_map将所有数组值转换为整数
  • array_unique删除重复值
  • array_filter删除零值
  • implode将所有值加入 IN 选择


小智 5

更安全.

$galleries = array(1,2,5);
array_walk($galleries , 'intval');
$ids = implode(',', $galleries);
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
Run Code Online (Sandbox Code Playgroud)


Sup*_*Roy 5

如果我们正确地过滤输入数组,我们可以使用这个"WHERE id IN"子句.像这样的东西:

$galleries = array();

foreach ($_REQUEST['gallery_id'] as $key => $val) {
    $galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
}
Run Code Online (Sandbox Code Playgroud)

如下例所示:在此输入图像描述

$galleryIds = implode(',', $galleries);
Run Code Online (Sandbox Code Playgroud)

即现在你应该安全使用 $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";


Mar*_*ery 5

Col. Shrapnel的PHP SafeMySQL库在其参数化查询中提供了带类型提示的占位符,并包括几个方便的用于处理数组的占位符。该?a占位符膨胀出的阵列,以逗号分隔的转义字符串*的列表。

例如:

$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);
Run Code Online (Sandbox Code Playgroud)

*请注意,由于MySQL执行自动类型强制,因此SafeMySQL将上面的id转换为字符串并不重要-您仍将获得正确的结果。


归档时间:

查看次数:

535096 次

最近记录:

7 年,2 月 前