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

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

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

我怎样才能生成这个查询string用于MySQL?

谨防! 这个答案包含一个严重的SQL注入漏洞。 不要使用这里介绍的代码示例,也不要确保任何外部input都已过滤。

 $ids = join("','",$galleries); $sql = "SELECT * FROM galleries WHERE id IN ('$ids')"; 

使用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); 

使用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(); 

说明:

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

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

 expr IN (value,...) 

我们可以build立一个expression式放置在我们的数组() 。 请注意,括号内必须至less有一个值,否则MySQL将返回一个错误; 这相当于确保我们的input数组至less有一个值。 为了帮助防止SQL注入攻击,首先生成一个? 为每个input项目创build一个参数化查询。 这里我假设包含你的ID的数组叫做$ids

 $in = join(',', array_fill(0, count($ids), '?')); $select = <<<SQL SELECT * FROM galleries WHERE id IN ($in); SQL; 

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

 SELECT * FROM galleries WHERE id IN (?, ?, ?) 

再次注意到有一个? 为input数组中的每个项目。 然后,我们将使用PDO或MySQLi来准备和执行上面提到的查询。

使用带有string的IN()运算符

由于绑定的参数,在string和整数之间很容易改变。 对于PDO,不需要改变; 对于MySQLi,将str_repeat('i',更改为str_repeat('s',如果需要检查string。

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

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

整型:

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

string:

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

假设您事先已经正确地清理了您的input内容

 $matches = implode(',', $galleries); 

然后调整你的查询:

 SELECT * FROM galleries WHERE id IN ( $matches ) 

引用值取决于你的数据集。

使用:

 select id from galleries where id in (1, 2, 5); 

一个简单for each循环将工作。

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

作为Flavius Stef的回答 ,你可以使用intval()来确保所有的id都是int值:

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

对于具有转义函数的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)"); 

对于准备好声明的PDO:

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

更安全。

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

如果我们正确地过滤了input数组,我们可以使用这个“WHERE ID IN”子句。 像这样的东西:

 $galleries = array(); foreach ($_REQUEST['gallery_id'] as $key => $val) { $galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT); } 

像下面的例子一样: 在这里输入图像描述

 $galleryIds = implode(',', $galleries); 

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

我们应该注意SQL注入漏洞和一个空的情况 。 我将如下处理。

对于一个纯数字数组,使用适当的types转换即每个元素的intvalfloatvaldoubleval 。 对于stringtypesmysqli_real_escape_string() ,如果您愿意,也可以应用于数字值。 MySQL允许数字以及datevariables作为string

要在传递给查询之前正确地转义值,请创build一个类似于以下内容的函数:

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

这样的function很可能已经在您的应用程序中可用,或者您已经创build了一个。

清理string数组,如:

 $values = array_map('escape', $gallaries); 

数组数组可以使用intvalfloatvaldoubleval进行消毒,

 $values = array_map('intval', $gallaries); 

最后build立查询条件

 $where = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0; 

要么

 $where = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0; 

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

并将其添加到最终查询中:

 $query = 'SELECT * FROM `galleries` WHERE ' . $where; 

提示 :如果你想显示所有的logging(没有过滤)的情况下,而不是隐藏所有行的数组,而不是隐藏所有行,只需在三元的假部分取代1

用于PHP的Shrapnel的SafeMySQL库在其参数化查询中提供了types提示的占位符,并且包含了几个用于处理数组的便利占位符。 ?a占位符将一个数组扩展为以逗号分隔的转义string列表*。

例如:

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

*请注意,由于MySQL执行自动types强制转换,因此SafeMySQL将上面的id转换为string并不重要 – 您仍然可以得到正确的结果。

您可能有表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)

 SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0 

这样你就可以pipe理一个简单的n2m数据库关系,不需要额外的表格,只需要使用SQL,而不需要使用PHP或其他编程语言。

因为原来的问题涉及到一个数组数组,我正在使用一个string数组我不能让给定的例子工作。

我发现每个string都需要用单引号封装在IN()函数中。

这是我的解决scheme

 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 (\')包装每个数组variables,然后使数组爆炸。

注: $status在SQL语句中没有单引号。

有可能是一个更好的方式来添加引号,但这个工程。

除了使用IN查询外,在IN查询中有两个选项可能会导致SQL注入漏洞。 你可以使用循环来获得你想要的确切数据,或者你可以使用OR情况下的查询

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

更多的例子:

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

简单地使用IN子句将起作用。

SELECT * FROM galleries WHERE id IN(1,2,3,4);

防止SQL注入的基本方法是:

  • 使用预准备语句和参数化查询
  • 转义不安全variables中的特殊字符

使用预处理语句和参数化查询查询被认为是更好的做法,但是如果你select转义字符方法,那么你可以尝试下面的例子。

您可以使用array_map$galleries中的每个元素添加单引号来生成查询:

 $galleries = array(1,2,5); $galleries_str = implode(', ', array_map(function(&$item){ return "'" .mysql_real_escape_string($item) . "'"; }, $galleries)); $sql = "SELECT * FROM gallery WHERE id IN (" . $galleries_str . ");"; 

生成的$ sqlvariables将是:

 SELECT * FROM gallery WHERE id IN ('1', '2', '5'); 

注意: mysql_real_escape_string ( 如其文档中所述)已在PHP 5.5.0中弃用,并且已在PHP 7.0.0中删除。 应该使用MySQLi或PDO_MySQL扩展。 另请参阅MySQL:select一个API指南和相关的FAQ以获取更多信息。 这个function的替代包括:

  • mysqli_real_escape_string()

  • PDO ::引用()