将PHP数组格式化为SQL的“IN”子句

6
我将尝试查询数据库中的记录,其中“product_id”包含在产品ID数组中。
该数组是多选输入(<select>)的邮寄结果,看起来像:
$clients = 
  Array ( 
    [0] => 80000016-1302638679
    [1] => 8000003B-1329924004
  )

我想把这个数组传递给一个SQL语句的“IN”子句,如下所示:
$sql = "SELECT * FROM sales WHERE product_id IN (".$clients.")";

...但是这样做不起作用(错误:Message: Array to string conversion)。

一些帖子建议使用此函数以适合SQL的方式格式化数组:

function format_array($array){
    return implode(', ', $array);
  }
}

Such as ...

$sql = "SELECT * FROM sales WHERE product_id IN (".format_array($clients).")";

这导致了以下查询:

SELECT * FROM sales WHERE product_id IN (80000016-1302638679, 8000003B-132992400)

......和以下错误:

where子句中的“8000003B”列未知

我做错了什么?非常感谢任何帮助!如果需要,我可以澄清问题 :)


1
你需要将80000016-1302638679放在引号中。 - sashkello
尝试使用https://dev59.com/0lLTa4cB1Zd3GeqPY0Wi。 - Rakesh Sharma
7个回答

7

尝试使用引号将您的ID括起来:

function format_array($array){
    return "'" . implode("', '", $array) . "'";
  }
}

正如cwallenpoole所指出的,如果您还没有对字符串进行转义,那么您应该对其进行转义。不进行字符串转义是非常危险的,特别是在您有一个公共应用程序的情况下。

请看下面的注释,为了防止注入攻击,您需要使用mysqli_escape_string()函数。 - garrettmurray

7

有更好的方法

你在评论中提到你正在使用CodeIgniter。除非你正在做一些非常复杂的事情,否则你没有实际理由在拥有内置where_in的情况下构建自己的查询。

如果那不起作用,那么就有老式的escape


好的,所以,大多数人都说你需要引用这些项目,并给你这个:

function createInClause($arr)
{
    return '\'' . implode( '\', \'', $arr ) . '\'';
}

但是如果你有可能会输入可疑的内容(例如'); DROP TABLE STUDENTS; --),那么这并不足够。为了防止这种情况,你需要确保检查SQL注入:

function createInClause($arr)
{
    $tmp = array();
    foreach($arr as $item)
    {
        // this line makes sure you don't risk a sql injection attack
        // $connection is your current connection
        $tmp[] = mysqli_escape_string($connection, $item);
    }
    return '\'' . implode( '\', \'', $tmp ) . '\'';
}

你好,感谢您详尽的回答!然而,当我使用该函数时,我收到以下错误提示:"mysqli_escape_string() 需要精确的2个参数"。如果有区别的话,我正在使用CodeIgniter。 - Andrew
@Andrew 对不起,我忘记了签名的更改。 - cwallenpoole
很遗憾,CodeIgniter的where_in对我来说行不通,因为查询相当复杂(涉及基于用户输入的许多情况的销售报告)。您是否知道mysqli_escape_string函数的connection变量是否已经存在于CodeIgniter中的某个地方?我宁愿不重新定义数据库连接,因为我知道CodeIgniter已经处理了这个问题(尽管可能没有将其作为变量直接提供)。希望这样说得清楚!再次感谢您的帮助,非常感谢您提供的出色答案! - Andrew
@Andrew CI也有一个解决方法。使用$this->db->escape - cwallenpoole

2
请使用此函数。
function format_array($array){
    return implode("','", $array);
  }
}

并且这个查询

$sql = "SELECT * FROM sales WHERE product_id IN ('".$clients."')";

这会将整个where子句包装在一个引号中,这样是行不通的。 - garrettmurray
@ garrettmurray 还要检查implode函数如果$array=array(456456,4569845934)中有两个项目;格式化数组将返回456456','4569845934然后$sql将是SELECT * FROM sales WHERE product_id IN ('456456','4569845934') - Garry
我的错,由于某种原因我错过了那一部分。=) - garrettmurray

2

您需要将80000016-1302638679用引号括起来,否则它会认为您正在进行减法运算。

return "'".implode("', '", $array)."'";

1

你需要将这些放在引号中,如下:

 SELECT * FROM sales WHERE product_id IN ('80000016-1302638679', '8000003B-132992400') 

1

你需要用引号包裹你的项目。以下是一个快速修复方法:

$clientIds = "";
foreach ($clients as $client) {
  $clientIds .= ($clientIds == "" ? "" : ", ") . "'".mysqli_escape_string($client)."'";
}

$sql = "SELECT * FROM sales WHERE product_id IN (".$clientIds.")";

0

将值用引号括起来,像这样:

 SELECT * FROM sales WHERE product_id IN ('80000016-1302638679', '8000003B-132992400')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接