【问题标题】:Getting a single output from cfquery when query column is cfqueryparam variable当查询列是 cfqueryparam 变量时从 cfquery 获取单个输出
【发布时间】:2016-07-28 20:35:53
【问题描述】:

我正在使用 ColdFusion 并尝试创建一个函数,让我可以获取特定帐户中特定列的值(每个帐户都有自己的记录/行)。

这样的函数可以正常工作:

<cffunction name="getColumnValueFromAccount" access="public" returntype="string" >
    <cfargument name="accountName" type="string" required="yes" />

    <cfquery name="getColumn" datasource="mydatasource">
        <!--- Note that the line below is 'hard-coded.' --->
        SELECT role_ExampleSystem
        FROM table_name
        WHERE (accountName = <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#accountName#'>)
    </cfquery>

    <!--- It's easy to return the column value when you know what its name was. --->
    <cfreturn getColumn.role_ExampleSystem > 

</cffunction>

但我真正想要的是一个函数,它允许我指定从哪个列名读取,并且不需要制作一堆几乎相同的 CF 函数,它们只是具有不同的硬编码 SELECT 参数。我在想它应该看起来像这样,但我在实际读取我认为它应该返回的单个字符串时遇到了麻烦。

<cffunction name="getColumnValueFromAccount" access="public" returntype="string" >
    <cfargument name="accountName" type="string" required="yes" />
    <!--- Trying to accept a column name as an argument --->
    <cfargument name="columnName" type="string" required="yes" />

    <cfquery name="getColumn" datasource="mydatasource">
        <!--- I'm trying to use cfqueryparam to add specify the column name to select. --->
        SELECT <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#columnName#'>
        FROM table_name
        WHERE (accountName = <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#accountName#'>)
    </cfquery>

    <!--- This line doesn't work. --->
    <cfreturn getColumn[#columnName#] >

</cffunction>

我认为您可以在 getColumn[#columnName#]getColumn[columnName] 这样的括号符号中使用变量,因为有人在 comment 中提到了它。但是当我自己尝试使用变量时,它并没有按预期工作。我收到此错误:

The value returned from the getColumnValueFromAccount function is not of type string. If the component name is specified as a return type, it is possible that either a definition file for the component cannot be found or is not accessible.

知道当我想获得 cfquery 的单个结果时应该采取什么路线,但我没有在查询的 SELECT 部分使用硬编码的列名吗?通常这个过程很简单,但是当你的列名是一个变量时,情况似乎有点不同。

【问题讨论】:

  • 我正在尝试使用 cfqueryparam 添加指定要选择的列名。 你不能那样做。 CFQueryparam 只能用在文字上,不能用在必须作为 sql 命令评估的东西上——比如表名或列名。
  • 这可能是问题的一部分,从技术上讲,我不需要 cfqueryparam 提供的 SQL 注入保护,因为 columnName 的 cfargument 将是我在另一个服务器端函数中指定的内容。无需清理输入,因为我知道这将是我写的有效内容。
  • 我按照您的建议删除了 cfqueryparam 并替换为 #variable# 然后使用 Mark A Kruger 的更正示例来说明如何使用括号表示法。看起来它正在按预期工作!我会在最后发布我所拥有的,以防将来对人们有所帮助。

标签: sql coldfusion cfquery cfqueryparam


【解决方案1】:

查询是数组的结构,如 queryname[key][1]。

由于向后兼容性,它首先可以工作。从一开始你可以做 queryname.columnname 和 CF 将输出该列查询的第一行。一旦切换到对象语法,它就不再那样工作了。

在你的 cfreturn 中试试这个:

getColumn[columnName][1]

注意 - 您的 cfreturn 示例中不需要井号。

【讨论】:

  • 此方法在我更改了我的columnName cfqueryparam 并将其替换为像#columnName# 这样的常规冷融合变量后有效。
  • 是的 - 抱歉,您的代码中没有看到这个问题。 cfqueryparam 将变量绑定到原始“类型” - 因此它不能用作列名。
  • 请记住,像这样在查询中使用列名将使您进入 SQL 注入(因为我可以传递直接在查询中动态使用的字符串)。因此,不允许将任何 USER 输入传递给函数。事实上,没有理由不选择每一列,让您的 cfreturn 整理出您回馈的内容吧?
  • 这很好。我试图最小化数据库必须发送的数据量,但老实说,现在我考虑一下,返回每个 role_ 列只会多几个字节,然后让我的函数查找它感兴趣的一个。
  • 是的,这就是要走的路——只要你可以轻松地消除这些攻击向量即可。 :)
【解决方案2】:

我的解决方案:

根据 Leigh 的建议,即我不能以尝试使用它的方式使用 cfqueryparam,以及 Mark A Kruger 的 answer,我能够修改我的代码并使其正常工作。现在看起来像这样:

<cffunction name="getColumnValueFromAccount" access="public" returntype="string" >
    <cfargument name="accountName" type="string" required="yes" />
    <cfargument name="columnName" type="string" required="yes" />

    <cfquery name="getColumn" datasource="mydatasource">
        SELECT #columnName#
        FROM table_name
        WHERE (accountName = <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#accountName#'>)
    </cfquery>

    <cfreturn getColumn[columnName][1] >

</cffunction>

它现在正确返回指定系统中的帐户角色,即如果帐户accountNameExampleSystem 中的admin,并且我将role_ExampleSystem 作为ColumnName 传递给函数,该函数将返回admin正如预期的那样。

警告:如果使用不当,我的解决方案可能会带来 SQL 注入风险!

在这样的 SQL 语句中使用 ColdFusion 变量不会提供任何防止 SQL 注入的保护,因此允许用户输入是一个非常糟糕的主意此处用于columnName 的数据。在我的情况下,这个函数只会被我编写的其他服务器端函数调用,并且用于columnName 的数据将被硬编码在服务器端函数中。另一方面,accountName 是用户指定的,因此它位于 cfqueryparam 中很重要。

另一种更安全的解决方案:

Mark A Kruger mentioned 最好选择您可能需要的每一列,然后阅读您真正感兴趣的那一列。这似乎是个好主意。毕竟,获取记录的每个(相关)列不太可能是比我的单列示例更大的数据库调用——除非您的数据库具有包含大量列的大量记录。您也可以这样做,并且作为一个附带好处,您不必担心在cfquery 中使用常规冷融合#variable# 可能会打开您的SQL 注入。

阅读每个人的答案和 cmets 非常有启发性。希望这个问题及其答案可以帮助有兴趣在 ColdFusion 中做类似事情的其他人!

【讨论】:

  • 是的,我正要说不要打扰这个函数:) 按照 Mark 的建议只返回所有列要简单得多。除非该表包含一堆 blob 列,否则这应该是一件大事。
  • 同意。所有这些使 SQL 只返回一个值的工作有点毫无意义,因为现在带宽非常便宜。
  • 另外,与选择不同列的一堆不同语句相比,数据库可能更有效地缓存执行计划。特别是如果您使用的是 cfqueryparam。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 2016-07-03
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 2021-03-05
相关资源
最近更新 更多