如何在 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 要求取消了连接到 b
中 null
行的任何 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');
}
对于常规 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 要求取消了连接到b
中null
行的任何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');
}