使用PDO在GET变量中传递多个值
使用PDO在GET变量中传递多个值
我对PDO存在一个问题,我已经被这个问题困扰了相当长的时间,我真的很希望能得到一个答案。
以这个例子为例:
我正在将一个ID数组绑定到PDO语句中,以便在MySQL的IN语句中使用。
数组可以是这样的:$values = array(1,2,3,4,5,6,7,8);
安全的数据库变量应该是:$products = implode(',', $values);
所以,$products将是一个值为'1,2,3,4,5,6,7,8'的字符串。
语句将会是:
SELECT users.id FROM users JOIN products ON products.user_id = users.id WHERE products IN (:products)
当然,$products将会被绑定到语句中作为:products。
然而,当语句被编译和绑定值时,它实际上会变成这样:
SELECT users.id FROM users JOIN products ON products.user_id = users.id WHERE products IN ('1,2,3,4,5,6,7,8')
问题是它将IN语句中的所有内容作为一个字符串执行,因为我已经准备好了以逗号分隔的值来绑定到语句中。
实际上我需要的是:
SELECT users.id FROM users JOIN products ON products.user_id = users.id WHERE products IN (1,2,3,4,5,6,7,8)
我唯一能做到的就是将值直接放在字符串中而不绑定它们,然而我确信一定有更简单的方法来做到这一点。
问题的原因是在使用PDO时,无法直接将多个值传递给GET变量。根据之前提到的答案,有三种解决方法。
第一种方法是在查询中构建查询语句来处理变量大小的列表。例如,可以使用quoted、逗号分隔的列表和find_in_set函数来实现。然而,对于大数据集,这种方法会有很大的性能影响,因为表中的每个值都必须转换为字符类型。
第二种方法是创建一个用户定义的函数来解析逗号分隔的列表,这可能是三种方法中最好的选择,特别是如果有很多查询依赖于in(...)子句。
第三种方法是在绑定参数时,确保字符串中没有空格。
以上是对问题出现的原因和解决方法的整理。在使用PDO时,如果需要将多个值传递给GET变量,可以考虑使用这些方法来解决。
问题出现的原因是当需要在GET变量中传递多个值时,使用PDO进行查询时,如果不知道要绑定的变量数量,就会变得有些混乱。
解决方法是将sprintf和count智能地结合起来。通过使用sprintf函数,可以动态生成包含适当数量占位符的查询语句。然后,使用count函数来确定要绑定的变量的数量,并将其与生成的查询语句一起传递给PDO的prepare方法。
具体来说,可以按照以下步骤解决该问题:
1. 使用sprintf函数生成包含适当数量占位符的查询语句。例如,可以使用以下代码生成查询语句:
$query = sprintf("SELECT users.id FROM users JOIN products ON products.user_id = users.id WHERE products IN (%s)", implode(',', array_fill(0, count($values), '?')));
这里的$values是包含要绑定的值的数组。
2. 使用count函数确定要绑定的变量的数量。例如,可以使用以下代码获取$values数组中的元素数量:
$numValues = count($values);
3. 使用PDO的prepare方法准备查询语句,并将生成的查询语句和要绑定的变量的数量传递给它。例如,可以使用以下代码准备查询:
$stmt = $pdo->prepare($query); $stmt->execute($values);
这里的$pdo是PDO对象,$values是包含要绑定的值的数组。
通过这种方法,可以动态地在GET变量中传递多个值,并使用PDO进行查询,而不需要手动计算要绑定的变量的数量。这样,可以更方便地处理不确定数量的参数。
在使用PDO时,有时需要在GET变量中传递多个值。下面是解决这个问题的方法:
一种处理这种情况的好方法是使用`str_pad`在SQL查询中为每个值放置一个`?`。然后,将值的数组(在这种情况下是`$values`)作为`execute`方法的参数传递进去:
$sql = ' SELECT users.id FROM users JOIN products ON products.user_id = users.id WHERE products.id IN ('.str_pad('',count($values)*2-1,'?,').') '; $sth = $dbh->prepare($sql); $sth->execute($values); $user_ids = $sth->fetchAll();
这样,您可以更好地使用预处理语句,而不是直接将值插入到SQL中。
如果只想要唯一的用户ID,而不是重复的用户ID,则建议将查询的第一行改为`SELECT DISTINCT users.id`。
为什么需要在`count()`上做`*2-1`而不仅仅是`-1`?
这是因为`str_pad`的第二个参数是"填充长度",以字符为单位。由于您想要在每个值之间放置一个问号和一个逗号,所以计算出来的长度是`count($values)*2-1`。如果您愿意,也可以使用`str_repeat('?,',count($values)-1).'?'`。
我更喜欢使用`implode(',', array_fill(1,count($values),'?'))`,因为这样减少了出错的可能性,并且不需要单独处理最后一个元素。
您还可以使用`str_repeat()`,它可能是列出的方法中最高效的:`rtrim(str_reapeat('?,', count($values)), ',')`。
什么情况下直接在查询中放置变量是一个好主意?我们真的要为SQL注入防范措施而争论吗?为什么一个主张不应该这样做的解决方案会有17个赞成票?
你理解代码有误。它并没有将变量直接放在查询中。这正是这个解决方案的关键。它为每个变量放置一个问号,以便PDO可以准备实际的语句。是的,我们喜欢PDO的安全措施,这个解决方案提供了一种使用它们的方法。
`implode(',', array_fill(0, count($values), '?'))`