【问题标题】:How to securely write a Joomla SELECT query with an IN condition in the WHERE clause?如何在 WHERE 子句中安全地编写带有 IN 条件的 Joomla SELECT 查询?
【发布时间】:2018-09-17 03:09:07
【问题描述】:

对于常规 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)
    ;

【问题讨论】:

    标签: php mysql joomla3.0 query-builder where-in


    【解决方案1】:

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

    而不是这个 -

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

    【讨论】:

      【解决方案2】:

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

      在 Joomla Stack Exchange 的 How to Use IN Clause in Joomla Query 上查看我非常全面的答案。

      相反,您的查询可以安全/可靠地写成:

      $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 关键字或猴子扳手字符,因此不需要引用/转义这些静态值。
      • from() 方法不需要 qn() 出于同样的原因。
      • 使用 Joomla 略短的 leftJoin() 而不是长手 join('LEFT',...) 语法。更好的是,因为您的 WHERE 要求取消了连接到 bnull 行的任何 a 行,所以使用 innerJoin() 更合适。
      • 由于两个表中要连接的列具有相同的名称,您可以享受USING 更甜美的语法。这也意味着您在查询中的其他位置引用 id 时无需指定表别名。
      • where() 方法,正如我文章开头提到的,可以静态编写。即使您传入一个您之前在脚本中静态编写的数组,您也可以像这样安全地使用它:

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

      • setLimit() 可以满足您的要求,因为该方法经过硬编码,可通过 Joomla 将传入的值转换为整数。

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

      echo $query->dump();
      

      要运行基本诊断检查,您可以使用以下命令,但永远不要向公众显示 $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');
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-02
        • 2011-10-16
        • 1970-01-01
        • 1970-01-01
        • 2019-08-08
        • 1970-01-01
        • 2013-07-07
        • 1970-01-01
        相关资源
        最近更新 更多