将PHP数组implode成mysql IN条件

4

I have a function like the following:

public function foo ($cities = array('anaheim', 'baker', 'colfax') )
{
    $db = global instance of Zend_Db_Adapter_Pdo_Mysql...

    $query = 'SELECT name FROM user WHERE city IN ('.implode(',',$cities).')';
    $result = $db->fetchAll( $query );
}

这个方法在$cities为空数组时会出现问题。

为了避免这个错误,我使用了以下方法来打破查询逻辑:

$query = 'SELECT name FROM user';
if (!empty($cities))
{
    $query .= ' WHERE city IN ('.implode(',',$cities).')';
}

但这并不是很优雅的做法。我觉得应该有更好的方法通过列表进行过滤,但我不确定如何操作。有什么建议吗?


3
如果用户提交包含 '(SQL注入)或逗号的城市名称,这里也会发生错误...你需要用 ' 包裹它们。 - Pekka
这样做是完全可以的。如果没有城市,你就不需要WHERE子句... - Felix Kling
2
我认为看起来不错,但你可以使用许多类来制作漂亮的预处理查询。至少要转义你的字符串!请参考http://php.net/manual/en/function.mysql-real-escape-string.php。 - Brad
除了Pekka提到的问题,我认为根据输入添加WHERE子句并没有不雅之处。在我看来,这比得到一个无意义的“所有”WHERE子句要好。但是,即使对于可变计数的IN,我仍然更喜欢使用预处理语句(通常使用implode(',',array_fill(0,count($args),'?'))。 - Wrikken
2
不要使用mysql_real_escape_string。如果$db是Zend_DB的实例,请使用它的方法来正确编码查询或构建准备好的参数化查询。关于where子句:你真的想让你的foo()方法既选择一些城市又选择所有城市吗?就我个人而言,我不喜欢这样,这是两个独立的问题->两种方法。 - VolkerK
这是我完全同意的做法。 - ITroubs
3个回答

7
如果您最终决定使用select对象,->where()方法实际上会为您处理数组。仍需要检查数组中是否有项目,但这使得代码更加简洁...
$select = $db->select()->from('user', 'name');

if ($cities) {
    $select->where('city IN (?)', $cities);
}

3
至少使用quote方法...
if ($cities) {
    $query .= sprintf('WHERE city IN (%s)', implode(',', array_map(array($db, 'quote'), $cities)));
}   

或者更理想的方法是使用Zend_Db_Select构建查询...
$select = $db->select()->from('user', 'name');

if ($cities) {
  foreach ($cities as $city) {
        $select->orWhere('city = ?', $city);
    }
}

1

你需要知道的是,从Zend_Db_Adapter :: quote的Zend Docs中:

“如果将数组作为值传递,则会对数组值进行引用, * 然后将其作为逗号分隔的字符串返回。”

因此,您可以执行以下操作,这也是正确引用的:

if ($cities) $query .= 'WHERE city IN ({$db->quote($cities}) ';

我喜欢一行代码 :)


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