如何在 WHERE 子句中使用 IN 条件安全地编写 Joomla SELECT 查询?

How to securely write a Joomla SELECT query with an IN condition in the WHERE clause?

对于常规 MySQL 命令,我们使用 SELECT foo WHERE bar IN (a,b,c)

如何使用 Joomla 的查询构建方法正确执行此操作?

我试过这个:

$query
    ->select(array('a.id', 'a.promo', 'a.harga', 'a.dp', 'a.image', 'a.teaser' , 'b.title','b.created'))
    ->from($db->quoteName('#__cck_store_form_paket_trip', 'a'))
    ->join('LEFT', $db->quoteName('#__content', 'b') . ' ON (' . $db->quoteName('a.id') . ' = ' . $db->quoteName('b.id') . ')')
    ->where($db->quoteName('b.catid') . ' IN '.$db->quote(.'(13,14,15)'.)
    ->order($db->quoteName($orderby) . ' '.$order)
    ->setLimit($limit,$start)
    ;

$db->quote 函数接受一个值或一个数组。您可以使用内爆函数尝试以下代码 -

而不是这个 -

$db->quote(.'(13,14,15)'.)

试试这个 -

$db->quote(array(13,14,15))

最终查询将是 -

$query
    ->select(array('a.id', 'a.promo', 'a.harga', 'a.dp', 'a.image', 'a.teaser' , 'b.title','b.created'))
    ->from($db->quoteName('#__cck_store_form_paket_trip', 'a'))
    ->join('LEFT', $db->quoteName('#__content', 'b') . ' ON (' . $db->quoteName('a.id') . ' = ' . $db->quoteName('b.id') . ')')
    ->where($db->quoteName('b.catid') . ' IN (' . implode(',', $db->quote(array(13,14,15))) . ')' )
    ->order($db->quoteName($orderby) . ' '.$order)
    ->setLimit($limit,$start)
    ;

IN 条件中引用静态值对于 "stability" 和 "security" 是完全没有用的。这些数据点不是注入攻击向量,因为它们是静态的。您的查询没有中断的风险,因为您已正确写入整数值。引用数组值只会增加不必要的代码膨胀,导致效率略有下降,并使您的代码更难阅读。

请参阅我在 Joomla Stack Exchange 上的非常全面的回答 How to Use IN Clause in Joomla Query

相反,您的查询可以safely/securely写成:

$query = $db->getQuery(true)
    ->select(["id", "a.promo", "a.harga", "a.dp", "a.image", "a.teaser", "a.title", "a.created"])
    ->from("#__cck_store_form_paket_trip a")
    ->innerJoin("#__content b USING (id)")
    ->where("b.catid IN (13,14,15)")
    ->order($db->qn($orderby) . ($order == "DESC" ? " DESC" : ''))
    ->setLimit($limit, $start);

解释:

  • select() 方法不包含任何 MySQL 关键字或 monkeywrenching 字符,因此 none 这些静态值需要是 quoted/escaped.
  • 出于同样的原因,from() 方法不需要 qn()
  • 使用 Joomla 的略短的 leftJoin() 语法代替长手写的 join('LEFT',...) 语法。更好的是,因为您的 WHERE 要求取消了连接到 bnull 行的任何 a 行的资格,所以使用 innerJoin().
  • 更合适
  • 因为要在两个 table 中连接的列具有相同的名称,所以您可以享受 USING 更甜美的语法。这也意味着您在查询的其他地方引用 id 时不需要指定 table 别名。
  • where()方法,我的post开头提到的,可以静态写。即使你传入一个你之前在脚本中静态编写的数组,你也可以像这样安全地使用它:

    ->where("b.catid IN (" . implode(',', $arrayOfIntegers) . ")")
    
  • 因为可以安全地假设 $orderby 是从用户输入派生的,所以您应该继续在 order() 方法中实现 qn()。因为 ASC 是默认的排序方向,所以我只在查询中有条件地写入 DESC (IOW,如果排序方向是 ASC,则省略它)。

  • setLimit() 的方式很好,因为 Joomla 对该方法进行了硬编码以将传入的值转换为整数。

如果您想查看生成的 sql 查询,请使用:

echo $query->dump();

要 运行 进行基本诊断检查,您可以使用以下内容,但永远不要向 [=77 显示 $query->dump() 或原始 $e->getMessage() 字符串=]!

// never show $query->dump() to the public
JFactory::getApplication()->enqueueMessage($query->dump(), 'info');
$db->setQuery($query);
try {
    if (!$result = $db->loadAssocList()) {
        echo "No Qualifying Rows";
    } else {
        echo "<table>";
            echo "<tr><th>", implode("</th><th>", array_keys($result[0])), "</th></tr>";
            foreach ($result as $row) {
                echo "<tr><td>", implode("</td><td>", $row), "</td></tr>";
            }
        echo "</table>";
    }
} catch (Exception $e) {
    // never show getMessage() to the public
    JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error');
}